将匿名/动态函数设置为菜单

2023-12-11

我想在 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);
    };
 }

当我单击菜单项时,出现以下异常:

“未找到脚本函数:函数名"

我得到了帮助匿名函数, 动态菜单 and 动态更新自定义菜单,但我不知道为什么它对我不起作用。

任何帮助将不胜感激。

Thanks.


Summary:

Google Apps 脚本运行在stateless环境。存储在全局对象中的任何内容都不会跨会话维护。如果您在会话期间向全局对象添加某些内容,则该内容在下一次会话运行中不可用。使用立即调用函数或全局范围内的调用函数来填充全局范围(this对象)在用户界面实际调用任何函数之前。

解释:

提到的解决方法[电子邮件受保护] in 本期评论#17以及田池在这个答案两者都利用闭包/立即调用函数(IIFE)填充全局范围。

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

  1. 菜单点击(按钮点击似乎跳过了步骤1和2,因此似乎不可拦截)

  2. 脚本编辑器中的所有脚本均被执行,并且全局函数名称列表this创建(在此步骤中,没有运行/调用任何函数,但所有脚本都已完全执行)。这相当于使用脚本加载网页:<script>...code.gs...</script>

  3. 检查当前调用的按钮/菜单的功能名称是否存在于全局中this,

  4. 如果存在,则执行该函数(即调用链接按钮/菜单的函数名称引用的函数)。这就像添加myFunction()在已加载脚本的末尾。如果没有找到,则抛出错误:Script function not found

  5. 脚本结束。这就像关闭加载的网页一样。所有“状态”都丢失了。没有全局范围或this被永久保存。

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

function onOpen(){
  this['a'] = () => 'a';
  SpreadsheetApp.getUi()
    .createMenu("Test")
    .addItem("Call function a","a")
    .addToUi()
}

这样就可以成功添加了a功能为Ui菜单,但请注意a仅添加到全局this scope during onOpen执行。这this然后在执行完成后丢失并且新的this(全局范围)在下次调用任何函数时创建(重复步骤 1 到 5)。因此,当单击菜单时,步骤 2 会创建一个新的this并寻找一个名为的函数a在所有脚本中,但找不到任何脚本,因为这是新创建的this没有a(因为onOpen已声明,但未执行,因此a没有添加到this这次)。

解决方案:

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

function onOpen(){
  SpreadsheetApp.getUi()
    .createMenu("Test")
    .addItem("Call function a","a")
    .addToUi()
}
(function IIFE(){
  this['a'] = () => 'a';
})(); 

上面的 IIFE 函数拦截了步骤 2“每次”,调用任何函数。所以a总是存在于this在步骤 3 时或之后。田池的解决方案,这是由installFunctions()在全球范围内。每次调用任何函数时都会执行该函数。同样的情况也适用于createMenuFunctions(this); in 评论#17.

文档摘录:

From 附加文档链接,

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

示例脚本:

/**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();
}

参考:

  • IIFE

  • 相关答案

  • 无状态与有状态

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将匿名/动态函数设置为菜单 的相关文章

  • Jest 中从未调用图像 onLoad 处理程序

    我正在尝试使用 Jest 测试将 dataUrl 加载到图像中 我正在使用 JSDOM 并按照说明添加resources usable 作为一个选项 如果我直接从 Node 运行该代码 则该代码可以工作 但是当我尝试在 Jest 中运行它时
  • 使用最新 Ember Data 版本中的 RESTSerializer 格式化 JSON

    我正在努力将我的 JSON munge 成正确的格式 为了说明这一点 我做了一个快速的 JSfiddle http jsfiddle net chrismasters NQKvy 638 http jsfiddle net chrismas
  • 如何监控浏览器中发出的所有自定义事件?

    我想监视网络浏览器中触发的所有自定义事件 任何标准浏览器都可以 需要明确的是 我知道您可以附加事件处理程序来查看何时触发 通常 事件 但如何可靠地检测嵌入对象或 jQuery 脚本是否触发自定义事件 我可以重构浏览器源代码来挂钩事件循环 但
  • 从 Angular 6 服务中绑定图像

    我有一个端点 它根据某些参数为我提供图像 这不是一个图像网址 而是一个普通图像 因此 当我到达邮递员中的端点时 作为响应 我收到一张图像 JPG 我是否可以在变量中接收该图像并将其绑定到 HTML 标签中 所有问题都有将图像 url 映射到
  • 画布图像遮罩/重叠

    在我的项目中 我必须使用画布在另一个相同尺寸和图案图像上实现一个不同的颜色图像 并且图像不是圆形或矩形形状 所有这些都是波浪形状的 它将应用于单个主背景图像 以便在每个主背景图像上显示多个图形onclick功能 重叠的图像应更改为另一种选定
  • 将参数传递给 jquery 单击事件中的回调函数[重复]

    这个问题在这里已经有答案了 直接进入正题 我有一个 jquery 事件监听器 如下所示 number click printNumber 和一个回调函数 function printNumber number console log num
  • AttachEvent 或 addEventListener - 存储在哪里?

    在 jQuery 中 如果我这样做 a click function Do something 点击事件存储在 a data events 我可以像这样获取它 jQuery each a data events function i eve
  • jQuery UI 对话框使用 setTimeout 自动关闭

    我试图让对话框在打开后三秒自动关闭 我尝试过以下方法 setTimeout mydialog dialog close 3000 这是在上下文中 acknowledged dialog dialog height 140 modal tru
  • 拖放图像上传在服务器上不起作用

    我正在尝试实现拖放图像上传 我在网上找到了一个相当简单的脚本并适合我的使用 在我的本地安装中 文件上传得很好 但在服务器上却不行 从我的调试尝试来看 SERVER HTTP X FILENAME 甚至没有被 php 设置 我尝试了以下方法
  • Javascript 访问 Disqus 评论文本框?

    我正在开发一个浏览器扩展 它应该允许我访问文本框中的评论 帖子 现在很多网站都使用 Disqus 作为评论方式 但在输入文本时我无法找到访问 Disqus 评论框的方法 Disqus API 也没有透露太多信息 有人知道访问它的方法吗 解决
  • Google Maps JS Api - b.get 不是函数错误(isLocationOnEdge)

    我想检查我的路线上是否有标记 所以我尝试使用 isLocationOnEdge 但收到 TypeError b get 不是函数 错误 这是我的代码 我尝试了几次更改但无法解决问题 var directionsDisplay new goo
  • 从 UnityWebGL jslib 返回字符串

    我想使用 jslib 来获取网址参数 像这样的代码 jslib GetUrl function var s var strUrl window location search var getSearch strUrl split var g
  • Flot 0.8.2 折线图 - 颜色错误

    我正在使用 Flot 折线图并设置它们的颜色 我发现了一个奇怪的错误 在前 3 种颜色之后 绘图对所有其他线条使用最后一种颜色 这不是正确的行为 更有趣的是图例显示了正确的颜色 这是一个已知的错误 var dataSet label d1
  • 自动调整元素 (div) 大小以适合水平内容

    我尝试谷歌搜索 但没有得到太多结果 我正在构建一个水平轮播 它在浮动的 LI 中显示图像 我想解决的问题是 每次我向轮播添加缩略图 我是延迟加载 时 我都需要重新计算轮播的宽度 以便所有浮动缩略图很好地并排排列 其一 我宁愿不必在 JS 中
  • NodeJS 中的缩进多行日志记录

    我要打印JSON stringify d 反对控制台 将上下文作为 Mocha 测试套件输出的一部分 当测试缩进时 我希望对象日志行向右缩进足够远 例如 3 4 个制表符空格 以便它们可以识别地位于右侧describe group 我怎样才
  • jVectorMap - 向下钻取地图 - 自定义背景

    我正在使用 jVectorMap 中的向下钻取地图 并且尝试将自定义背景颜色设置为地图的第二层 为了自定义主级别 我使用 main 参数 但我不知道如何将其扩展到地图的较低级别 提前致谢 马切伊 None
  • 使用重复模式捕获正则表达式

    我试图捕获字符串的所有部分 但我似乎无法正确处理 该字符串具有以下结构 1 22 33 中间有运算符的数字 可以有任意数量的术语 我想要的是 1 22 33 1 22 33 但我得到 1 22 33 22 33 我尝试过各种正则表达式 这是
  • JavaScript 比较中应使用哪个等于运算符(== 与 ===)?

    这个问题的答案是社区努力 help privileges edit community wiki 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 我在用着JSLint http en wikipedia org wiki JSLint
  • 在64位环境中加载32位进程

    我有以下几个问题 CHM 是 编译的 HTML 文件 我的 CHM 文件有一个启动 32 位应用程序的链接 CHM 文件是用 Javascript 编码的 这在 32 位操作系统环境中运行良好 但这在 64 位操作系统环境中不起作用 原因是
  • 网页执行回发时如何停止在注册表单上?

    我正在做我的最后一年的项目 其中 我在一页上有登录和注册表单 WebForm 当用户点击锚点时Sign Up下拉菜单ddlType 隐藏 和文本框 txtCustName txtEmail and txtConfirmPassword 显示

随机推荐

  • 同时下载多个页面?

    我想用Python编写一个脚本 它可以从数据库中获取url 并同时下载网页以加快速度 而不是等待每个页面一个接一个地下载 根据这个线程 Python 不允许这样做 因为称为全局解释器锁这可以防止多次启动相同的脚本 在投入时间学习 Twist
  • 无法从jupyterhub/jupyter笔记本调用tensorflow gpu,为什么?

    好吧 我认为八个小时足够我自己解决这个问题 所以我只想问大家 我在 jupyterhub 和 Jupyter Notebook 之外的名为 tensorflow 的虚拟环境中运行 tensorflow gpu 1 1 0 运行得很好 也就是
  • Scrapy CrawlSpider 基于 start_urls 的动态规则?

    我正在编写一个 Scrapy 抓取工具 它使用 CrawlSpider 来抓取网站 检查其内部链接 并抓取任何外部链接 域与原始域不同的链接 的内容 我设法用两条规则来做到这一点 但它们是基于正在爬网的网站的域 如果我想在多个网站上运行它
  • 当每一侧有不同数量的项目时,将弹性项目置于一行中居中

    如何实现图片上绘制的布局 例如 左侧 3 项 一项居中 两项在右侧 ul 是橙色 黑框是项目 ul display flex width 100 ul li Item 1 li li Item 2 li li Item 3 li li It
  • scala 集合:映射列表并携带一些状态?

    我似乎一直遇到这个问题 我想修改列表中的一些元素 但我需要在这样做时保留一些状态 因此地图不起作用 这是一个例子 scala gt val l1 List a b c d e f b c e b a l1 List String List
  • Arm 板上有两个以上的 SPI 设备,但只支持两个?

    我们其中一块板上的 Arm 处理器有一个 spi 端口 带有两条片选线 该处理器的数据表中提到它最多可以控制两个 spi 设备 是否可以使用 GPIO 作为附加 spi 设备的从选择 如何修改现有的库 设备驱动程序以支持此更改 到目前为止
  • Linux C++ 尝试使用绝对路径加载一个特定库,而所有其他库则使用相对路径链接

    我有以下问题 我正在尝试创建程序的可移植版本 因此我将 rpath 设置为 因此所有库都使用相对文件路径链接 这确实适用于除一个库之外的所有库 由于某种原因 只有当一个特定库存在于编译时链接的同一位置时 该程序才能工作 这是我自己写的 它的
  • 在 Flex Line 图表中显示数据点

    我有一个弹性折线图 有没有办法改变每个点的渲染并让它们始终显示 而不是必须将鼠标悬停在线条的某些部分上才能查看数据点的默认行为 几乎就像连接点类型视图 Try this
  • 使用 CGSizeMake 和 CGSize 有什么区别?这个比那个好吗?

    CGSize width 360 height 480 and CGSizeMake 360 480 似乎有同样的效果 一个比另一个更受青睐吗 有什么不同 The CGSize构造函数是 Swift 的扩展CGSize extension
  • Visual Studio 2022 发布窗口未检测身份验证状态

    我已经登录到 VS2022 因此也登录到 Azure 但在尝试发布应用程序时 我看到以下屏幕 从右上角可以看出我已经登录了 那么我什么时候得到这个 我什至尝试了这个建议link 我退出并删除了 localappdata IdentitySe
  • 可滚动的 JFree 域轴和自定义标记标签

    我有这段代码来绘制图表 效果很好 我这里需要两件事 在域轴 x 上我希望能够滚动 在标记上我看到一条粗粗的线 我希望能够看到该标记的一些可读文本 For now I see this output 缩放后我看到了这个 同样在域轴上我有毫秒值
  • 在 JavaScript 中重试 Promise 的通用解决方案

    我尝试给出一个重试承诺的通用解决方案 以下是我的方式 出现 未捕获 承诺 的错误 我该如何解决这个问题 function tryAtMost maxRetries promise let tries maxRetries return ne
  • SQL Server 2005 - 如何将图像数据类型转换为字符格式

    背景 我是一名软件测试人员 使用测试用例管理数据库 该数据库使用已弃用的图像数据类型存储数据 我对 SQL Server 比较缺乏经验 问题 具有富文本格式的字符数据存储为图像数据类型 目前 以人类可读格式查看这些数据的唯一方法是通过测试用
  • 在 PHP 中寻找加载依赖项/服务/配置的优雅方法?

    我正在构建一个 MVC PHP 框架 我想知道哪些是在我的类中加载所需内容的最佳实践 无论是其他类还是普通配置 到目前为止 我已经使用了单例 注册表以及最近的依赖注入容器 虽然许多人声称 DI 是可行的方法 但在我看来 它只是将组件之间的耦
  • ASP.NET 中的 OpenIDSelector 问题

    我正在尝试使用 asp net c 在我的网站中使用 OpenID 我正在使用 asp net v4 开发 asp net 表单网站 我遇到的问题是我的工具箱中的 openidselector 控件是由 dotnetopenauth dll
  • dbms_output.put() 的缓冲方式与 dbms_output.put_line() 不同吗?

    我使用 Aqua Data Studio 通过分散输出语句来调试存储过程 我在包中有一条违反完整性约束的删除语句 DELETE FROM x WHERE x ID an x with children 正如预期的那样 我的过程在该行失败并出
  • 为什么类的静态方法可以继承,而接口的静态方法不能继承?

    我知道在Java中静态方法就像实例方法一样被继承 不同之处在于当它们被重新声明时 父实现被隐藏而不是被覆盖 好吧 这是有道理的 然而 Java 教程注意到 接口中的静态方法永远不会被继承 为什么 常规方法和接口静态方法有什么区别 让我澄清一
  • php通过序列号进行页面导航

    任何人都可以帮助这个 php 页面导航脚本打开计算正常序列号吗 在这个脚本中有一个名为 page id 的变量 我希望这个变量按0 1 2 3 4 5等顺序存储真实的页面链接
  • 有没有办法在 EDM Designer 2010 中设置自定义复数形式?

    我正在使用 VS 2010 并且我有一个实体 Person 复数服务将其复数变为 People 我希望它是 Persons 有没有可以管理复数库的地方 不在 Visual Studio 中 no 与此同时 您可以下降到 API 级别并创建您
  • 将匿名/动态函数设置为菜单

    我想在 Google Sheets 插件中为动态菜单设置动态功能 我正在使用以下代码 function onOpen e var menu SpreadsheetApp getUi createAddonMenu for var i 0 i