4

我刚刚开始玩应用程序脚本和谷歌网络应用程序。我可以构建一个基本应用程序,其中设置了一个“静态”(因为需要更好的词)页面,如下所示:

function doGet() {
var app = UiApp.createApplication().setTitle('foo');
...set up widgets/etc
return app;
}
...handlers here

据我所知, doGet返回之前没有一个处理程序开始运行。这就是我的问题。我需要一个交互式页面,其中页面的内容由对下拉列表的第一个响应决定。换句话说,用户会看到一个下拉列表,他进行选择并点击“提交”,然后我必须根据该选择设置一个列表框。

所以,看起来我不能把我的任何逻辑放进去doGet,我基本上必须通过我的事件处理程序链接所有的逻辑:

function doGet() {
  ...set up first page and first submit handler
  return app;
}
function firstSubmitHandler(e) {
  .. respond to first submit handler, draw list boxes, set up second list handler
}
function secondSubmitHandler(e) {
  .. respond to second submit handler, yada
}

如果这是正确的,那就太疯狂了。我错过了什么吗?谢谢。

4

3 回答 3

2

这是您在创建新的“作为 Web 应用程序的脚本”时获得的示例脚本的一个小扩展。我所做的只是让初始单击处理程序向 Ui 添加另一个按钮,然后将另一个单击处理程序带入范围。您可以使用相同的概念来构建动态 UI。

// Script-as-app template, extended.
// doGet is exactly as supplied
function doGet() {
  var app = UiApp.createApplication();

  var button = app.createButton('Click Me');
  app.add(button);

  var label = app.createLabel('The button was clicked.')
                 .setId('statusLabel')
                 .setVisible(false);
  app.add(label);

  var handler = app.createServerHandler('myClickHandler');
  handler.addCallbackElement(label);
  button.addClickHandler(handler);

  return app;
}

// myClickHandler now contains a modified copy of doGet.
function myClickHandler(e) {
  //////////// Key concept: The UI app lives on after doGet exits
  var app = UiApp.getActiveApplication();

  var button = app.createButton('Click Me 2');
  app.add(button);

  var label = app.createLabel('The 2 button was clicked.')
                 .setId('statusLabel')
                 .setVisible(false);
  app.add(label);

  var handler = app.createServerHandler('myClickHandler2');
  handler.addCallbackElement(label);
  button.addClickHandler(handler);

  return app;
}

// myClickHandler2 is the original myClickHandler, as supplied
function myClickHandler2(e) {
  var app = UiApp.getActiveApplication();

  var label = app.getElementById('statusLabel');
  label.setVisible(true);

  app.close();
  return app;
}

如果这还不足以让您入门,请查看如何使用 Google UI Builder 和 Apps 脚本的清晰示例,以及 Serge 提供的示例。

于 2013-01-18T01:51:50.953 回答
2

在任何类型的 webapp 中,你响应来自客户端的请求,然后你就完成了。如果客户端想要交互,它需要发出新的请求。在大多数 webapps 中,这意味着向服务器发出 XHR 请求;应用程序脚本使用处理程序简化了这一点,但概念是相同的。

为什么这么疯狂?这就是世界上每个 webapp 的编写方式——服务器提供初始页面,如果存在交互性,页面会发出新请求并在服务器上运行更多东西。HTTP 被设计为无状态协议,即使有允许客户端和服务器之间持久连接的扩展,它们也很少使用(用于需要即时更新的聊天之类的事情),并且对于您的内容来说会非常缓慢和昂贵正在努力做。

如果你是从常规的桌面编程开始使用 webapps,这个模型一开始可能会很奇怪和不直观,但它对 Apps Script 来说并不是特别的。

于 2013-01-18T14:10:58.773 回答
1

无需重新加载 Google Apps 脚本网页即可检索 HTML 内容并将其动态注入页面。

设置空元素以接收新的页面内容

  <section id="ChgViewSection">
      <div id="PageOne"></div>
      <div id="PageTwo"></div>
      <div id="PageThree"></div>
      <div id="PageFour"></div>
      <div id="PageFive"></div> 
  </section>

最初将大多数元素设置为隐藏,style="display:none"

  <section id="ChgViewSection">
      <div id="PageOne" style="display:block"></div>
      <div id="PageTwo" style="display:none"></div>
      <div id="PageThree" style="display:none"></div>
      <div id="PageFour" style="display:none"></div>
      <div id="PageFive" style="display:none"></div>    
    </div>
  </section>

将一个元素设置为style="display:block"。那将是最初加载的页面。

创建用户界面以更改页面、菜单或选项卡。

<div id="tabs-nested-left">
  <div class="cb" id="tabSignIn" onclick="mainStart('SignInBody', 'SignIn')">Sign In</div>
  <div class="cb" id="tabInput" onclick="mainStart('InputBlock', 'InputForm')">Input</div>
  <div class="cb" id="tabReg" onclick="mainStart('RegisterBlock', 'Register')">Registration</div>
  <div class="cb" id="tabRegExpl" onclick="mainStart('Explain', 'Explain')">Registration Explanation</div>
  <div class="cb" id="tabContact" onclick="mainStart('ContactUs', 'Contact')">Security</div>
</div>

写一个<script>用于处理onclick事件。

<script>

function mainStart(ElmtToGoTo, FileToGet) {
   var currntShown = 'SignInBody'; //Create variable and set initial value
   //Hide the currently shown element first
   document.getElementById(currntShown).style.display = 'none';
   //
   currntShown = ElmtToGoTo;
   //display the element that will be shown.  No content is injected yet
   document.getElementById(ElmtToGoTo).style.display = 'block';

   var el = document.getElementById(ElmtToGoTo);
   // If element is empty get HTML and inject
   if (el.childNodes.length === 0) {
      //alert("it's empty!");
    //Run back end google .gs code to get new content
    google.script.run.withFailureHandler(onFailure)
      .withSuccessHandler(onGotHTML)
      .include(FileToGet);
  };

};

<script>

向您的 HTML 脚本添加失败和成功处理程序:

function onGotHTML(daHTML) {
  //alert("Got HTML File!");
  document.getElementById(currntShown).innerHTML=daHTML;
  };

function onFailure(error) {
  alert("on failure ran:" + error.message);
};

编写服务器端.gs代码:

function include(filename) {
  return HtmlService.createHtmlOutputFromFile(filename)
   .getContent(); 
};

单击选项卡时,当前显示的内容<div>将被隐藏,然后<div>显示要显示的内容,但尚无内容。如果<div>已经有内容,什么也不做。如果<div>为空,则运行 agoogle.script并从服务器获取内容。内容返回给客户端并注入到<div>成功处理程序onGotHTMLdocument.getElementById(currntShown).innerHTML=daHTML;

其中大部分是 DOM 操作和样式更改。但是使之成为可能的是从服务器检索文件内容。您需要与内容一起保存的文件才能注入<div>元素。当用户单击菜单项或选项卡时从服务器检索 HTML 内容可以避免预先加载所有内容。一个问题是 CSS 样式数据不能在以后添加,除非它inline(已经在标签中)。因此,您必须在页面首次加载时加载所有 CSS 样式文件,或者将样式设置放入元素中。您可以在页面加载后注入 HTML,并在不重新加载页面的情况下显示它,但您不能在页面加载后包含 CSS 文件并显示新样式。

我可能遗漏了一些东西,比如用于样式的 CSS 文件,但代码;HTML/样式;并显示总体策略。您可以像这样构建动态单页应用程序。

于 2014-03-05T21:15:46.803 回答