【问题标题】:Using triggers with custom functions on Google Apps Script在 Google Apps 脚本上使用带有自定义函数的触发器
【发布时间】:2020-11-20 07:11:46
【问题描述】:

我的脚本有问题,this question 得到了很好的回答。 基本上自定义函数不能调用需要授权的服务。但是,据我了解,如果我使用简单的触发器,例如 onEdit,它可以工作。

我检查了上一个问题中建议的文档,但是我没有成功地将它应用到我的代码中,您可以在下面看到:

function FileName (id) {
  var ss = DriveApp.getFileById(id);
  return ss.getName();
}

如何调整我的代码以使用简单的触发器?

Here is a sample sheet 复制了问题。

【问题讨论】:

  • 简单触发器也不能调用需要权限的服务。您需要使用可安装的触发器 => getValues(所有 id)和 setValues(所有文件名)。查看最佳实践和 JavaScript 数组。有关详细信息,请参阅tag info page
  • 您能提供使用可安装触发器的建议吗?
  • 我无法理解Using simple triggers with custom functions on Google Apps Script。我可以问你目标的细节吗?顺便说一句,从您的示例电子表格中,我认为您可能希望使用 FileName 的功能作为 Google 电子表格的自定义功能。我的理解正确吗?
  • @Tanaike 我的目标是每次在电子表格中注册新 URL 时获取文件的名称。关于函数 FileName,最好使用自定义函数,但是对于需要授权的服务是不可能的。
  • 感谢您的回复。根据您的回复,我提出了实现您目标的解决方法。你能确认一下吗?如果这不是您期望的方向,我深表歉意。

标签: google-apps-script google-sheets


【解决方案1】:

我相信你的目标如下。

  • 您想将FileName 的函数用作Google 电子表格的自定义函数。
    • 您希望在将文件 ID 放入“B”列时自动检索文件名。
    • 您想将文件名放在“C”列中。

问题和解决方法:

很遗憾,在使用自定义函数时,在目前的规范中,除了几个需要授权的方法(例如其中一种是UrlFetchApp.)之外,大部分方法都不能使用。这样,您的脚本中的DriveApp.getFileById(id) 不能与自定义函数一起使用。但是有一个解决方法。在自定义函数中,可以使用 UrlFetchApp。在这个答案中,我想建议使用带有 UrlFetchApp 的 Web 应用程序作为授权的包装器。通过这种方式,可以使用 Web 应用程序进行授权。所以你的函数可以由自定义函数运行。

用法:

1。准备脚本。

请将以下脚本复制并粘贴到脚本编辑器中并保存。

const key = "samplekey"; // This is a key for using Web Apps. You can freely modify this.

// This is your function.
function FileName_(id) {
  var ss = DriveApp.getFileById(id);
  return ss.getName();
}

// Web Apps using as the wrapper for authorizing.
function doGet(e) {
  let res = "";
  if (e.parameter.key === key) {
    try {
      res = FileName_(e.parameter.id);
    } catch (err) {
      res = `Error: ${err.message}`;
    }
  } else {
    res = "Key error.";
  }
  return ContentService.createTextOutput(JSON.stringify({value: res}));
}

function Filename(id) {
  const webAppsUrl = "https://script.google.com/macros/s/###/exec"; // Please set the URL of Web Apps after you set the Web Apps.

  const res = UrlFetchApp.fetch(`${webAppsUrl}?id=${id}&key=${key}`);
  if (res.getResponseCode() != 200) throw new Error(res.getContentText());
  return JSON.parse(res.getContentText()).value;
}

2。部署 Web 应用程序。

  1. 在脚本编辑器上,通过“发布”->“部署为 Web 应用”打开一个对话框。
  2. “执行应用程序为:”选择“我”
    • 由此,脚本以所有者身份运行。
  3. “谁有权访问应用程序:”选择“任何人,甚至匿名”
    • 在这种情况下,请求 Web 应用程序不需要访问令牌。但在此示例脚本中,使用了向 Web 应用请求的密钥。
  4. 单击“部署”按钮作为新的“项目版本”。
  5. 自动打开“需要授权”对话框。
    1. 点击“查看权限”。
    2. 选择自己的帐户。
    3. 点击“此应用未验证”中的“高级”。
    4. 点击“转到###项目名称###(不安全)”
    5. 点击“允许”按钮。
  6. 点击“确定”。
  7. 复制 Web 应用程序的 URL。就像https://script.google.com/macros/s/###/exec
    • 当您修改 Google Apps 脚本时,请重新部署为新版本。这样,修改后的脚本就会反映到 Web 应用程序中。请注意这一点。
  8. 请将https://script.google.com/macros/s/###/exec的URL设置为上述脚本的url。请重新部署 Web 应用程序。这样,最新的脚本就会反映到 Web 应用程序中。所以请注意这一点。

3。测试此解决方法。

将文件ID放入单元格“A1”时,请将=filename(A1)作为自定义函数放入单元格中。这样,脚本就会运行并返回响应值。

注意:

  • 上面的示例脚本是一个简单的示例脚本,用于测试您的脚本。因此,当您想使用各种方法时,这篇文章可能会很有用。

  • 请使用此脚本启用 V8。

  • 作为其他方法,我认为当手动将文件ID放入“B”列时,可以使用可安装的OnEdit触发器。示例脚本如下。请设置工作表名称。并且请将触发器安装到installedOnEdit 的功能上。 Ref 这样,当文件 ID 被放到 sheetName 的“B”列时,文件 ID 被放到“C”列。

      function installedOnEdit(e) {
        const sheetName = "Sheet1";
        const range = e.range;
        const sheet = range.getSheet();
        if (!(sheet.getSheetName() == sheetName && range.getColumn() == 2 && range.getRow() > 1)) return;
        const value = range.getValue();
        let res = "";
        try {
          res = DriveApp.getFileById(value).getName();
        } catch(e) {
          res = e.message;
        }
        range.offset(0, 1).setValue(res);
      }
    

参考资料:

【讨论】:

  • 感谢@Tanaike,一如既往的精彩。我最终使用了更简单的解决方案,即您在 Notes 中添加的解决方案。为了将来参考,如果我想将结果设置为另一列,我只需将range.offset(0,1) 更改为另一个偏移量,例如range.offset(0,3)(它将结果向前移动 3 列)。
  • 我注意到此解决方案仅在我手动更改时有效,而不是在公式更改单元格内容时有效。在这行解决方案中,有没有办法在单元格自动更改时触发或仅在我手动编辑时触发?
  • @abutremutante 感谢您的回复。当您想在公式更新单元格时运行该函数时,在这种情况下,我认为需要使用时间驱动触发器。使用时间驱动触发器,它会检查您要更新的单元格。但如果这不是您期望的方向,我很抱歉。
  • 感谢您的建议,我也考虑过,但在我的情况下,文件可能会在一分钟或更短的时间内被删除,所以我认为编辑触发器会更好地工作
【解决方案2】:

documentation 可以看出,简单的触发器无法访问也不需要授权的服务

您必须改用installable triggers

但是工作流程与自定义函数有很大不同。

在您的具体情况下,您可以实施例如当正在编辑 A 列中的单元格(即插入新 URL)时 - 正在找到相应的文件名并将其返回到 D 列中。

您可以在event objects 的帮助下检索插入新 URL 的值和行。

示例:

function FileName (event) {
  var id = event.value;
  var ss = DriveApp.getFileById(id);
  var row = event.range.getRow();
  var sheet = event.range.getSheet();
  // for column D:
  var column = 4;
  var returnCell = sheet.getRange(row,column);
  returnCell.setValue(ss.getName());
}

对于使用可安装的 onEdit 触发器 - 按照 here 的说明,通过继续 Edit > Current project's triggers 将其绑定到此函数。

【讨论】:

  • 感谢您提供非常完整的答案。我按照你的建议做了,你可以在示例文件中看到。按照说明编辑了当前项目触发器,使用了相同的代码,但我仍然收到“异常:您无权调用 DriveApp.getFileById。所需权限:(googleapis.com/auth/drive.readonly || googleapis.com/auth/drive)(第 8 行)。 ”。第 8 行如下: var ss = DriveApp.getFileById(id);你设法让它工作吗?可以分享一下文件吗?
  • 如果您将其绑定到可安装的onEdit 触发器,则该代码可以正常工作。但与自定义函数相反,您不能像=FileName(A1) 这样在单元格中键入,您也不能从脚本编辑器手动运行代码 - 当您在列中添加或修改值时它会自动运行可安装触发器在人员授权下运行谁创建了它,并且只有此人可见。如果我在您的函数中安装触发器,我将无权访问您云端硬盘上的文件 - 所以您必须将可安装的 onEdit 触发器绑定到函数 FileName (event)
  • 顺便说一句,如果您不想将该函数仅应用于新 URL,而是应用于工作表中已存在的所有 URL,请考虑不使用触发器,而是设置手动运行函数,一次返回所有当前 URL 的文件名。它可以运行,例如在button click.
  • 感谢您解释我不能使用 =FileName(A1),因为我正在使用。什么是正确的合成器?或者我什至不需要调用该函数,它应该自动运行(顺便说一下它没有运行......)?
  • 是的,它应该自动运行 - 前提是您正确安装了 onEdit 触发器。但是触发器会触发事件 - 在您的情况下,将新 URL 添加到 A 列中的单元格中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多