Google Apps Script EventHandlers with userdata

Google Apps Script EventHandlers with userdata

本文关键字:with userdata EventHandlers Script Apps Google      更新时间:2023-09-26

我正在使用Google Apps脚本为Google电子表格制作一些自定义UI。

我正在尝试制作一个抽象的"向导"UI,该UI具有任意面板数组,然后在底部有一个"后退"和"下一步"按钮,该按钮会根据您所在的"页面"更改面板的可见性。

我需要某种机制,以便当您从向导的一页移动到下一页时,我可以在当前"页面"上调用一个函数说"我现在要离开你,请保存你的状态",类似于下一个"页面"说"设置好自己,你即将变得可见"(类似于 onShow(), onHide())。

但是,我正在努力弄清楚如何从后退和下一步按钮的事件处理程序中做到这一点。据我所知,访问 UI 元素或将字符串(通过"隐藏"UI 元素)传递到事件处理程序中非常容易。

这是我目前拥有的相关代码:

/*
*********************************************************************
*/
function createWizard(pages) {
  app = UiApp.getActiveApplication();
  var currIdx = app.createHidden("currentPanelIndex", 0).setId("CurrentPanelIndex");
  var minIdx = app.createHidden("minPanelIndex", 0);
  var maxIdx = app.createHidden("maxPanelIndex", pages.length);
  app.add(currIdx);
  app.add(minIdx);
  app.add(maxIdx);
  var buttPanel = app.createHorizontalPanel();
  var backButton = app.createButton("Back"); 
  var nextButton = app.createButton("Next"); 
  buttPanel.add(backButton).add(nextButton);
  var mainPanel = app.createVerticalPanel();
  for (var i = 0; i < pages.length; i++) {
    pages[i].setId("Panel"+i).setVisible(false);
    mainPanel.add(pages[i]);
  }
  mainPanel.add(buttPanel);
  mainPanel.setCellVerticalAlignment(buttPanel, UiApp.VerticalAlignment.BOTTOM);
  mainPanel.setCellHorizontalAlignment(buttPanel, UiApp.HorizontalAlignment.RIGHT);
  app.add(mainPanel);
  // create handler to respond to events
  var clickHandler = app.createServerClickHandler("doBack")
    .addCallbackElement(currIdx)
    .addCallbackElement(minIdx)
    .addCallbackElement(maxIdx);
  backButton.addClickHandler(clickHandler);  
  var clickHandler = app.createServerClickHandler("doNext")
    .addCallbackElement(currIdx)
    .addCallbackElement(minIdx)
    .addCallbackElement(maxIdx);
  nextButton.addClickHandler(clickHandler);
  updateVisibility(currIdx, minIdx, maxIdx)
}
/*
*********************************************************************
*/
function doBack(eventInfo) {
  app = UiApp.getActiveApplication();
  var parameter = eventInfo.parameter;
  var currentPanel = Math.round(Number(parameter.currentPanelIndex));
  var minPanel = Math.round(Number(parameter.minPanelIndex));
  var maxPanel = Math.round(Number(parameter.maxPanelIndex));
  if (currentPanel > minPanel) {
    currentPanel--;
    // Store the new value
    app.getElementById("CurrentPanelIndex").setValue(String(currentPanel));
    updateVisibility(currentPanel);
  }
  return app;
}
/*
*********************************************************************
*/
function doNext(eventInfo) {
  app = UiApp.getActiveApplication();
  var parameter = eventInfo.parameter;
  var currentPanel = parseInt(parameter.currentPanelIndex);
  var minPanel = Math.round(Number(parameter.minPanelIndex));
  var maxPanel = Math.round(Number(parameter.maxPanelIndex));
  Logger.log(currentPanel);
  if (currentPanel < maxPanel) {
    currentPanel++;
    // Store the new value
    app.getElementById("CurrentPanelIndex").setValue(String(currentPanel));
    updateVisibility(currentPanel, minPanel, maxPanel);
  }
  return app;
}
/*
*********************************************************************
*/
function updateVisibility(currentPanel, minPanel, maxPanel)
{
  for (var i = minPanel; i < maxPanel; i++) {
    if (i == currentPanel) {
      app.getElementById("Panel"+i).setVisible(true);
      // I want to do something like panel[i].onShow()
    }
    else {
      app.getElementById("Panel"+i).setVisible(false);
      // I want to do something like panel[i].onShow()
    }
  }  
}

请注意,我认为我无法扩展 UI 元素以能够进行"onShow"或"onHide"回调。我也看不出如何将回调作为字符串传递!

如有必要,我可以发布更多代码,但是如果我以错误的方式处理这个问题,我很乐意从头开始,所以我当前的实现细节相对不重要。

免责声明,我很擅长C++,C#,Lua等,但几乎是JavaScript的新手,所以我可能错过了一些完全明显的东西!

我认为你的方法可能太复杂了......您在用户界面中创建的所有小部件都可以在不同的面板中从一开始就创建,然后您的处理程序函数只需要"播放"它们的可见性。从用户 pov 来看,就像 UI 完全不同,但您有一个包含所有小部件的唯一 callbackElement。这是我很久以前建议的一个非常基本的小示例,它基于相同的原理模拟选项卡面板。

这 4 个面板位于一个垂直面板中,因此每个面板都占据完全相同的位置,给人一种内容正在更改的错觉。

我没有时间建议完整的演示代码,但告诉我这种方法是否适合您的需求。

<小时 />

按照您的评论编辑:

由于您已经有处理程序来处理两个按钮上的previous/next,我要做的就是在每个"页面"上复制 2 个相同的按钮,它们都具有相同的 2 个处理程序但不同的 ID。这样布局将保持不变,但您可以使用 e.parameter[source] 知道哪个"页面"确实触发了处理程序函数。如果您知道该页面,并且所有小部件都有连贯的索引,那么您可以采取的具体操作没有限制。例如,从第 3 页切换到第 4 页将被识别,因为处理程序函数的源将是button_next_3的,并且(始终例如)将数据从此面板写入 SS 上的工作表 3。

希望我足够清楚,我认为这样的概念没有任何限制。是吗?