【问题标题】:Custom function won't refresh as inputs are changed更改输入时自定义功能不会刷新
【发布时间】:2019-07-04 19:34:04
【问题描述】:

我有一个自定义函数,可以找到另一个单元格的值并显示它。当源单元格改变时,函数不反映。

https://docs.google.com/spreadsheets/d/1wfFe__g0VdXGAAaPthuhmWQo3A2nQtSVUhfGBt6aIQ0/edit?usp=sharing

刷新谷歌表格

function findRate() {
  var accountName = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange(1,1).getValue(); //determine the account name to use in the horizontal search
  var rateTab = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Rates'); //hold the name of the rate tab for further dissection
  var rateNumColumns =rateTab.getLastColumn(); //count the number of columns on the rate tab so we can later create an array
  var rateNumRows = rateTab.getLastRow(); //count the number of rows on the rate tab so we can create an array
  var rateSheet = rateTab.getRange(1,1,rateNumRows,rateNumColumns).getValues(); //create an array based on the number of rows & columns on the rate tab
  var currentRow = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getActiveCell().getRow(); //gets the current row so we can get the name of the rate to search
  var rateToSearch = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange(currentRow,1).getValue(); //gets the name of the rate to search on the rates tab
  for(rr=0;rr<rateSheet.length;++rr){
    if (rateSheet[rr][0]==rateToSearch){break} ;// if we find the name of the 
      }
  for(cc=0;cc<rateNumColumns;++cc){
    if (rateSheet[0][cc]==accountName){break};
      }
  var rate = rateSheet[rr][cc] ; //the value of the rate as specified by rate name and account name
  return rate;
}

如果我在汇率选项卡中更改汇率,我需要自定义函数来识别新汇率并更新其值

【问题讨论】:

  • 自定义函数被确定性地评估。根据谷歌的说法,如果一个人不接受任何参数,那么它就不需要重新计算。解决方案?传递论据!您显然依赖电子表格中的单元格进行计算,因此请明确说明,例如C4: =FINDRATE(A4)。那么当A4改变时,C4中的这个公式也会改变。

标签: google-apps-script google-sheets custom-function


【解决方案1】:
  • 您想在编辑Rates 的工作表名称的单元格时重新计算=findRate() 的自定义函数。

如果我的理解是正确的,那么添加以下示例脚本如何?请认为这只是几个答案之一。

解决方案:

为了重新计算自定义函数,在这个答案中,=findRate() 的公式被使用 OnEdit 事件触发器运行的脚本覆盖(在这种情况下,它是简单的触发器。)。由此,执行重新计算。但是,当公式直接被相同的公式替换时,不执行重新计算。所以我使用了以下流程。

  1. 从“预计收入”表中检索所有具有=findRate() 公式的单元格区域。
  2. 清除范围的公式。
  3. 将公式放入范围内。

通过这个流程,当编辑“Rates”表的单元格时,通过自动运行onEdit()重新计算=findRate()的自定义函数。

示例脚本:

请将以下脚本复制并粘贴到脚本编辑器中。 然后,请编辑Rates 的工作表名称的单元格。这样,onEdit() 将由 OnEdit 事件触发器自动运行。

function onEdit(e) {
  var range = e.range;
  if (range.getSheet().getSheetName() == "Rates" && range.rowStart > 1 && range.columnStart > 1) {
    var sheetName = "Projected Revenue"; // If you want to change the sheet name, please modify this.
    var formula = "=findRate()";// If you want to change the function name, please modify this.

    var sheet = e.source.getSheetByName(sheetName);
    var ranges = sheet.createTextFinder(formula).matchFormulaText(true).findAll().map(function(e) {return e.getA1Notation()});
    sheet.getRangeList(ranges).clearContent();
    SpreadsheetApp.flush();
    sheet.getRangeList(ranges).setFormula(formula);
  }
}

注意:

  • onEdit(e) 由 OnEdit 事件触发器运行。所以当你直接运行onEdit(e)时,就会出现错误。请注意这一点。
  • 在此示例脚本中,作为示例,即使编辑了“Rates”表的第 1 行和“A”列,也不会重新计算自定义函数。如果你想修改这个并给出你想编辑的范围的限制,请修改上面的脚本。

参考资料:

如果我误解了您的问题并且这不是您想要的结果,我深表歉意。

补充:

TheMaster's comment 的提议已反映到脚本中。当sheet.createTextFinder(formula).matchFormulaText(true).replaceAllWith(formula)可以使用时,我也认为流程成本会大大降低。但在我的环境中,似乎需要清除一次公式才能刷新自定义函数,即使使用flush() 也是如此。所以我提出了上面的流程。

但是,现在我可以注意到使用 TextFinder 的 replaceAllWith() 的解决方法。所以我想补充一下。此变通方法的流程如下。

  1. 使用replaceAllWith()=findRate()的所有值替换为Projected Revenue工作表中的值。
    • 在这种情况下,作为测试用例,将公式替换为sample
  2. 使用replaceAllWith()sample 替换为=findRate()

通过这个流程,我可以确认 =findRate() 已重新计算。而且,这种情况似乎不需要flush()

示例脚本:

请将以下脚本复制并粘贴到脚本编辑器中。 然后,请编辑工作表名称Rates 的单元格。这样,onEdit() 将由 OnEdit 事件触发器自动运行。

function onEdit(e) {
  var range = e.range;
  if (range.getSheet().getSheetName() == "Rates" && range.rowStart > 1 && range.columnStart > 1) {
    var sheetName = "Projected Revenue";
    var formula = "=findRate()";
    var tempValue = "sample";

    var sheet = e.source.getSheetByName(sheetName);
    sheet.createTextFinder(formula).matchFormulaText(true).replaceAllWith(tempValue);
    sheet.createTextFinder(tempValue).matchFormulaText(true).replaceAllWith(formula);
  }
}

【讨论】:

  • @TheMaster 感谢您的评论。是的。正如您所说,使用replaceAllWith() 可以降低流程成本。但起初,在我的环境中,似乎需要清除一次公式才能刷新自定义函数,即使使用了flush()。所以我提出了上述流程。但是,现在我找到了使用replaceAllWith() 的解决方法。所以我添加了一个示例脚本。你能确认一下吗?在这种情况下,似乎不需要flush()。根据您的建议,脚本变得更加简单。非常感谢。
  • @Tanaike ,非常感谢您在这方面的帮助!这以我需要的确切方式更新。我想知道您是否建议以简洁的方式编辑您提供的代码以跨多个工作表更新 findRate() 函数?实际上,我有一个针对多个帐户(十几个)的“预计收入”标签
  • @Alex F 感谢您的回复。虽然我无法理解您的详细情况``我有一个电子表格中其他工作表的多个帐户(十几个), when you want to refresh findRate()``的“预计收入”选项卡,当您将var sheet = e.source.getSheetByName(sheetName);修改为@添加脚本的 987654358@,电子表格中所有工作表的 findRate() 被刷新。如果这不是您想要的结果,我深表歉意。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-11
  • 1970-01-01
  • 2019-05-31
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多