我刚刚开始使用应用脚本和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
}
如果这是对的,那就太疯狂了。我错过了什么吗? 感谢。
答案 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 /风格;并显示整体战略。您可以像这样构建动态单页面应用程序。