Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/474.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-apps-script/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Google Sheets插件:使用Google应用程序脚本将匿名/动态功能设置为菜单_Javascript_Google Apps Script_Google Sheets - Fatal编程技术网

Javascript Google Sheets插件:使用Google应用程序脚本将匿名/动态功能设置为菜单

Javascript Google Sheets插件:使用Google应用程序脚本将匿名/动态功能设置为菜单,javascript,google-apps-script,google-sheets,Javascript,Google Apps Script,Google Sheets,我想在Google sheets插件中为动态菜单设置动态功能。我正在使用以下代码: function onOpen(e) { var menu = SpreadsheetApp.getUi().createAddonMenu(); for (var i = 0; i < array.length; i++) { const element = array[i]; var functionName = "_" + elemen

我想在Google sheets插件中为动态菜单设置动态功能。我正在使用以下代码:

function onOpen(e) {
  var menu = SpreadsheetApp.getUi().createAddonMenu();
  
  for (var i = 0; i < array.length; i++) {
        const element = array[i];
        var functionName = "_" + element.name;
        var args = element.args;
        
        this[functionName] = dynamicItem(args); //didn't work
        //this[functionName] = function () {myopen(args);} //didn't work
        //eval("function " + functionName + "() { myopen('" + args + "') }"); //didn't work
        menu.addItem(element.name, functionName);
      }
   menu.addToUi();
 }

 function dynamicItem(args) {
    return function () {
       myopen(args);
    };
 }
开启功能(e){
var menu=SpreadsheetApp.getUi().createAddonMenu();
对于(var i=0;i
单击菜单项时,出现以下异常:

“找不到脚本函数:函数名”

我得到了,和的帮助,但我不知道为什么它对我不起作用

任何帮助都将不胜感激

谢谢。

总结: Google应用程序脚本在一个环境中运行。全局对象中存储的任何内容都不会跨会话进行维护。如果在会话期间向全局对象添加了内容,则该内容在下一次会话运行中不可用。在用户界面实际调用任何函数之前,使用立即调用的函数或全局范围中的调用函数填充全局范围(
对象)

说明: ..。@bbtv.com先生和Tanaike先生在中提到的解决方案都使用闭包/立即调用函数(IIFE)填充全局范围

要理解这一点,您需要了解何时读取和加载脚本函数名。以下步骤按顺序进行:

  • 按钮点击/菜单点击

  • 执行脚本编辑器中的所有脚本,并创建全局
    中的函数名列表(在此步骤中,没有运行/调用函数,但所有脚本都已完全执行)。这相当于用脚本加载网页:
    …code.gs…

  • 检查当前调用的按钮/菜单的功能名称是否存在于全局

  • 如果存在,则执行该功能(即调用链接按钮/菜单的功能名称所指的功能)。这类似于在已加载的脚本末尾添加
    myFunction()
    。如果未找到,则抛出错误:
    脚本函数未找到

  • 脚本结束。这就像关闭加载的网页。所有“状态”都将丢失。没有全局作用域或
    被永久存储

  • 使用
    此[function name]
    动态添加菜单项时,在添加函数时要意识到这一点很重要。如果在
    onOpen
    期间添加它,则
    onOpen
    执行期间具有全局范围内的功能,但在
    onOpen
    脚本执行完成后,它立即丢失

    function onOpen(){
      this['a'] = () => 'a';
      SpreadsheetApp.getUi()
        .createMenu("Test")
        .addItem("Call function a","a")
        .addToUi()
    }
    
    这将成功地将
    a
    函数添加到
    Ui
    菜单,但请注意,
    a
    仅在执行期间添加到全局
    范围。此
    将在执行完成后丢失,并在下次调用任何函数时创建一个新的
    (全局范围)(重复步骤1至5)。因此,当单击按钮时,步骤2创建一个新的
    this
    ,并在所有脚本中查找名为
    a
    的函数,但找不到任何函数,因为新创建的
    this
    没有
    a
    (因为
    onOpen
    已声明,但未执行,因此
    a
    这次不会添加到
    中)

    解决方案: 在步骤2期间或之前,您需要将函数添加到全局
    this

    function onOpen(){
      SpreadsheetApp.getUi()
        .createMenu("Test")
        .addItem("Call function a","a")
        .addToUi()
    }
    (function IIFE(){
      this['a'] = () => 'a';
    })(); 
    
    上面的IIFE函数“每次”截取步骤2,任何函数都被调用。因此,
    a
    总是在步骤3时或之后出现在
    this
    中。在Tanaike的解决方案中,这是通过
    installFunctions()完成的
    在全局范围内。每次调用任何函数时都会执行该函数。注释17中的
    createMenuFunctions(this);
    也是如此

    文件摘录: 从

    警告:当onOpen(e)函数运行时,将加载整个脚本并执行所有全局语句。这些语句在与onOpen(e)相同的授权模式下执行,如果模式禁止,则会失败。这将阻止onOpen(e)如果发布的加载项未能添加其菜单项,请查看浏览器的JavaScript控制台中是否引发错误,然后检查脚本以查看onOpen(e)函数或全局变量是否调用AuthMode.NONE中不允许的服务

    示例脚本: 参考资料:
    修改点:
    • 在您的脚本中,当打开电子表格时,
      onOpen(e)
      只运行一次。这样,当选择菜单时,功能就不会安装。我认为这就是您出现问题的原因
    • 为了运行动态安装的功能,每次都需要运行创建菜单的脚本。这似乎是由于当前的规范
    当上述各点反映到脚本中时,它将变成如下所示

    修改脚本:
    function installFunctions(){
    //样品
    var数组=[{name:“sample1”,args:“sample1”},{name:“sample2”,args:“sample2”},{name:“sample3”,args:“sample3”}];
    var menu=SpreadsheetApp.getUi().createMenu(“示例”);
    对于(var i=0;i/**Runs every time any script function is called*/
    (function IIFE(scope) {
      'use strict';
      scope['options'] = ['a', 'b', 'c']; //pollute current scope
      options.forEach(
        option =>
          (scope[option] = () =>
            SpreadsheetApp.getUi().alert(`You clicked option ${option}`))
      );
    })(this);//pass global scope
    
    function onOpen() {
      const testMenu = SpreadsheetApp.getUi().createMenu('Test');
      options.forEach(option =>
        testMenu.addItem('Call function ' + option, option)
      );
      testMenu.addToUi();
    }
    
    function installFunctions() {
      
      // Samples
      var array = [{name: "sample1", args: "sample1"}, {name: "sample2", args: "sample2"}, {name: "sample3", args: "sample3"}];
      
      var menu = SpreadsheetApp.getUi().createMenu("sample");
      for (var i = 0; i < array.length; i++) {
        const element = array[i];
        var functionName = "_" + element.name;
        var args = element.args;
        this[functionName] = dynamicItem(args);
        menu.addItem(element.name, functionName);
      }
      menu.addToUi();
    }
    
    installFunctions(); // This function is run when the Spreadsheet is opened and each menu is selected.
    
    function onOpen() {}
    
    function dynamicItem(args) {
      return function () {
        Browser.msgBox(args);  // Sample script.
        // myopen(args);
      };
    }
    
       function onOpen() {
          var ui = SpreadsheetApp.getUi() ;
          var menu = ui.createMenu("Choose") ;
          Options.forEach( O => menu.addItem(O[0], O[1]) ) ;
          menu.addToUi() ;
        }
        
        var Options = [] ;
        
        (function() {
          let items = ['X','Y','Z'] ;
          /*  or for example: JSON.parse(PropertiesService.getScriptProperties().getProperty("items")) ; /**/
          items.forEach( function(item) {
            let funcName = 'Choose$'+item ;
            Options.push([item,funcName]) ;
            this[funcName] = () => Handle(item) ;
          }) ;
        })() ;
        
        const Handle = it => console.log("we got %s", it) ;