apps-script:在网络应用中创建“动态”页面?

时间:2013-01-18 00:10:19

标签: javascript google-apps-script

我刚刚开始使用应用脚本和Google网络应用。我可以构建一个基本应用程序,其中“静态”(缺少更好的单词)页面设置如下:

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
}

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

3 个答案:

答案 0 :(得分: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;
}

如果这还不足以让你开始,请查看a clear example of how to use Google UI Builder and Apps script,以及Serge提供的示例。

答案 1 :(得分:2)

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

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

如果您要使用常规桌面编程来访问webapps,这个模型一开始可能很奇怪而且不直观,但它对于Apps Script来说并不特别。

答案 2 :(得分:1)

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

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

  <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>为空,请运行google.script并从服务器获取内容。内容将返回给客户端,并使用成功处理程序<div>onGotHTML

注入document.getElementById(currntShown).innerHTML=daHTML;

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

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