我怎么能与其父母(侧边栏)沟通页面?

fde*_*ego 4 google-docs google-sheets google-apps-script google-apps-script-addon google-apps-script-web-application

我正在将我的剧本转换成一个补充.其中一个需求是配置模板,因此我编写了一个侧栏,用于启动字段选择器.由于侧边栏没有足够的空间容纳选择器,我必须通过在侧边栏中创建的模式对话框启动它,方法是在服务器端调用此代码:

var html = HtmlService.createHtmlOutputFromFile('TemplatePicker.html')
  .setWidth(600).setHeight(425);
SpreadsheetApp.getUi().showModalDialog(html, 'Select the file with the template');
Run Code Online (Sandbox Code Playgroud)

我的问题是,一旦用户选择文件,当我拥有所选文件的ID时,我无法将该ID传递给侧边栏.我试图调用someJSFunctionOfSidebar(id)parent.someJSFunctionOfSidebar(id),但它没有工作,所以我终于结束了值传递到服务器端,并从那里重新加载侧边栏,但它很慢,产生的效果是丑陋的.

我的问题是:

有没有办法将客户端级别的值从创建的模式对话框传递SpreadsheetApp.getUi().showModalDialog给其父级?也许这不是它的父母,这也是它不起作用的原因.

Mog*_*dad 8

也许这不是它的父母,这也是它不起作用的原因.

对 - 这里实际上没有DOM父/子关系.侧边栏和模态对话框都是从服务器端脚本启动的,并且是独立的.但是,它们都可以与服务器通信,因此您可以使用存储转发技术将选择器的结果传递到侧边栏.

基本理念:

  • 一旦请求选择器启动,侧边栏就会开始轮询服务器以获取选择器的结果.
  • 选择器的结果将被发送到服务器,使用google.script.run.
  • 服务器将临时存储结果 - 这可能像全局变量一样简单,具体取决于您的情况.
  • 一旦有结果,下一个轮询将检索它.

请查看如何从加载项中轮询Google文档以了解轮询器的基本概念.

消息序列图


The*_*ter 8

问题:

尽管具有相同的起源,但侧边栏和模式对话框(兄弟)无法进行通信。

解决方案:

window.top即使父级是跨源的,也可以通过祖先父级从模式对话框获取对侧边栏 html 的引用。从那里,可以

  • 直接互相沟通
  • 用于window.postMessage()相互交流

在没有互相引用的情况下,仍然可以通过以下方式进行通信:

  • 服务器和脚本属性服务。然而,在这里,其中一个需要以设定的时间间隔轮询服务器以获取来自另一个的任何更新(如此处所示
  • 使用cookies/localstorage进行相互通信

读书:

示例脚本(使用跨源框架直接访问window.top):

addOn.html [侧边栏]

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Addon</title>
    <style>
      #spinner {
        display: none;
        background-color: tomato;
        position: absolute;
        top: 1%;
        width: 100%;
        justify-items: center;
      }
    </style>
  </head>
  <body>
    <div id="spinner"><p>Loading modal dialog...</p></div>
    <div id="output"></div>
    <script charset="utf-8">
      google.script.run.withSuccessHandler(spinner).testModal();
      function spinner(e) {
        document.getElementById('spinner').style.display = e || 'flex';
      }
      (async () => {
        //After modal dialog has finished, receiver will be resolved
        let receiver = new Promise((res, rej) => {
          window.modalDone = res;
        });
        var message = await receiver;
        document.querySelector('#output').innerHTML = message;
        //Do what you want here
      })();
    </script>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

modalAddOn.html [模态对话框/选择器]

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title></title>
  </head>
  <body>
    Modal Dialog
    <script>
      (function findSideBar(limit) {
        let f = window.top.frames;
        for (let i = 0; i < limit; ++i) {
          try {
            if (
              f[i] /*/iframedAppPanel*/ &&
              f[i].length &&
              f[i][0] && //#sandboxFrame
              f[i][0][0] && //#userHtmlFrame
              window !== f[i][0][0] //!== self
            ) {
              console.info('Sidebar found ');
              alert('Removing loadbar and closing self');
              var sidebar = f[i][0][0];
              sidebar.spinner('none'); //Remove sidebar spinner
              sidebar.modalDone('Modal says Hi'); //Modal has finished
              google.script.host.close();
            }
          } catch (e) {
            console.error(e);
            continue;
          }
        }
      })(10);
    </script>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

代码.gs [服务器]

function testModal() {
  SpreadsheetApp.getUi().showModelessDialog(
    HtmlService.createHtmlOutputFromFile('modalAddOn')
      .setHeight(500)
      .setWidth(300),
    ' '
  );
}

function onOpen(e) {
  SpreadsheetApp.getUi()
    .createMenu('Sidebar')
    .addItem('Show Add-On', 'showSidebar')
    .addToUi();
}

function showSidebar() {
  SpreadsheetApp.getUi().showSidebar(
    HtmlService.createTemplateFromFile('addOn.html').evaluate()
  );
}
Run Code Online (Sandbox Code Playgroud)

相关问题: