addTimer not working with global app in GAS - google-apps-script

I read about the (undocumented) addTmer and would like to use it for updating the UI.
The example at Auto refresh Google Apps Scripts webapp UI? does work well
// This code works
function doGet(e)
{
var app = UiApp.createApplication().setTitle('Test addTimer - createApplication in doget');
var appLocal = app;
var handler = appLocal.createServerHandler("update");
appLocal.addTimer(handler , 4000);
var label = appLocal.createLabel(new Date()).setId("label");
appLocal.add(label);
return appLocal;
}
function update(e)
{
var appLocal = UiApp.getActiveApplication();
// var appLocal = app;
appLocal.getElementById("label").setText(new Date());
var handler = appLocal.createServerHandler("update");
appLocal.addTimer(handler , 1000);
return appLocal;
}
but if I move createApplication out of doGet() into a global variable, an 'unexpected error' will occur at runtime.
Without addTimer it IS possible to move createApplication out of doget() into global scope.
// This code will crash at runtime
var app = UiApp.createApplication().setTitle('Test addTimer , createApplication outside doGet');
function doGet(e)
{
var appLocal = app;
var handler = appLocal.createServerHandler("update");
appLocal.addTimer(handler , 4000);
var label = appLocal.createLabel(new Date()).setId("label");
appLocal.add(label);
return appLocal;
}
function update(e)
{
var appLocal = UiApp.getActiveApplication();
// var appLocal = app;
appLocal.getElementById("label").setText(new Date());
var handler = appLocal.createServerHandler("update");
appLocal.addTimer(handler , 1000);
return appLocal;
}
As I've seen global use of
var app = createApplication();
and i suppose more people would like to use addTimer as well, I post my experience here.
Maybe someone can explain WHY this is a problem.

when you call a service outside of any function, this call is executed each time any function is called, that's to say when doGet is called but also when the handler function is called and also when the timer triggers a script execution.
It means that you are calling UiApp.createApplication() 2 (and more) times... this is not a good idea and generates an 'unexpected error'.
by the way, what would be the advantage of that approach ?
Uiapp is designed to work with a main service call and handlers, each handler getting the active instance using getActiveApplication() why are you trying to use it differently?

Related

Automatically close a Google Apps Script UiApp after five seconds

I want to automatically close this UiApp after a certain number of seconds:
function showConfirmationDialogue() {
var app = UiApp.createApplication().setHeight('80').setWidth('400');
app.setTitle('test');
var panel = app.createVerticalPanel();
app.add(panel);
var doc = SpreadsheetApp.getActive();
doc.show(app);
// this part doesn't seem to work
Utilities.sleep(5000);
app.close();
return app;
}
Thanks!
The Ui you create is shown when you call doc.show(app) and the only way you can update it or close it is to use a handler function that ends with a return app.
So it is not possible to do what you want from the same function that creates the UI since it is "returned" only one time.
I know only one trick that can achieve what you want that is using a handler trigger source that will call a closing handler function automatically using a "special" property of the checkBox widget. Here is the code, it uses a checkBox that you can of course make invisible in your final code.
function showConfirmationDialogue() {
var app = UiApp.createApplication().setHeight('80').setWidth('400');
app.setTitle('test');
var panel = app.createVerticalPanel();
app.add(panel);
var handler = app.createServerHandler('closeWindow');
var chk = app.createCheckBox('checkBox to set invisible in real function').setValue(false,true).addValueChangeHandler(handler);
app.add(chk);
chk.setValue(true,true)//.setVisible(false);
var doc = SpreadsheetApp.getActive();
doc.show(app);
}
function closeWindow(){
Utilities.sleep(5000);
var app = UiApp.getActiveApplication().close();
return app;
}
You can use the same procedure to modify the UiApp instance in any way, change a Label text, add a widget... anything you want.

how to get value of Hidden object

I need global variable in google script, to hold page ID, like a string. Here, they suggested to use object Hidden for this purpose. I can create this object and set its value.
Code to achieve the same :
function doGet(e) {
var app = UiApp.createApplication();
//Get current indentificator
var mid = 'page-id';
app.add( app.createHidden('mid').setValue(mid).setId('mid'));
return app;
}
But how can I get this value from another function?
For example :
function maketbl(){
var app = UiApp.getActiveApplication();
app.(?!)
}
Thanks!
I see that your requirement is to have functionality similar to that of global variables. I suggest that you use script properties, user properties or the cache service to accomplish this feat. An example is below
ScriptProperties.setProperty('special', 'sauce'); // Use this to set the property
var specialValue = ScriptProperties.getProperty('special'); // use this to access the property
Try the bellow code:
function doGet(e) {
var app = UiApp.createApplication();
var mid = 'page-id';
var hidden = app.createHidden('mid').setValue(mid).setId('mid');
app.add(hidden);
//Create your handler
var handler = app.createServerHandler('maketbl');
handler.addCallbackElement(hidden)
//Create a button to trigger your function
app.add(app.createButton().setText("go forest").addClickHandler(handler));
return app;
}
function maketbl(e){
var app = UiApp.getActiveApplication();
//Retrieve the hidden field
var hidden = app.getElementById("mid");
//Show the value stored at e.parameter.mid where mid is the name of the field
var dialogBox = app.createDialogBox().setText(e.parameter.mid);
dialogBox.setPopupPosition(100, 100);
dialogBox.show();
return app;
}
Live version here.

doPost Twice in Google Apps Script?

I have a web-deployed form written in Google Apps Script with doGet and doPost. In the doPost, the code checks if the user has filled in the form correctly (e.g. not leaving certain things blank). If not, it highlights the things that need to be fixed and adds a warning label. If everything is all right, it writes the form data to a spreadsheet.
The problem is that it doesn't seem like doPost can be called again if the user fixes the problems.
Any thoughts? Thanks!
EDIT: I am using UiService
EDIT: Here is a very simplified version of the app:
function doGet(e) {
var app = UiApp.createApplication();
var mainForm = app.createFormPanel().setId('mainForm');
var formContent = app.createVerticalPanel().setId('formContent');
var userName = app.createTextBox().setId('userName').setName('userName');
var passport = app.createFileUpload().setName('passport');
var submitButton = app.createSubmitButton('submit here');
var submitButtonWarning = app.createLabel('Something is wrong.').setId('submitButtonWarning')
.setVisible(false);
formContent
.add(userName)
.add(passport)
.add(submitButton)
.add(submitButtonWarning);
mainForm.add(formContent);
app.add(mainForm);
return app;
}
function doPost(e) {
var app = UiApp.getActiveApplication();
var userName = e.parameter.userName;
var passport = e.parameter.passport;
if (userName == 'no') {
app.getElementById('submitButtonWarning').setVisible(true);
app.add(app.getElementById('formContent'));
return app;
} else {
app.getElementById('submitButtonWarning').setVisible(false);
app.add(app.getElementById('formContent'));
return app;
}
return app;
}
I think you are just adding the wrong UI element to the app in your doPost.
Instead of
app.add(app.getElementById('formContent'));
use
app.add(app.getElementById('mainForm'));

using and modifying global variables within handler functions

Hello everyone out there,
I can use global variables within a handler function, however I cannot modify them "globally" within than function.
In code below, after the first click it will show the number 1001 (the handler reads, increments and shows the right result).
But, any further clicks will always show 1001, so the handler keeps reading the original globalVar value: it doesn't get modified as I was expecting.
Anything I can do to fix this?
var globalVar = 1000;
function testingGlobals() {
var app = UiApp.createApplication();
var doc = SpreadsheetApp.getActiveSpreadsheet();
var panel = app.createVerticalPanel().setId('panel');
app.add(panel);
panel.add(app.createButton(globalVar).setId("globalVar").addClickHandler(app.createServerHandler("chgGlobal").addCallbackElement(panel)));
doc.show(app)
}
function chgGlobal(e) {
var app = UiApp.createApplication();
globalVar++;
app.getElementById("globalVar").setText(globalVar);
return app;
}
You can not increment Global Variables this way, as every time a handler executes, Global variable is initialized and then manipulated.
You can use hidden formfields to hold the a variable which you can change in handler, and it will be persistent as long as the app is open.
e.g
function testingGlobals() {
var app = UiApp.createApplication();
var doc = SpreadsheetApp.getActiveSpreadsheet();
var panel = app.createVerticalPanel().setId('panel');
var myVar = app.createHidden().setValue('0').setName('myVar').setId('myVar');
panel.add(myVar);
app.add(panel);
panel.add(app.createButton('0').setId("globalVar").addClickHandler(app.createServerHandler("chgGlobal").addCallbackElement(panel)));
doc.show(app)
}
function chgGlobal(e) {
var app = UiApp.createApplication();
gloabalVar = parseInt(e.parameter.myVar);
gloabalVar ++;
app.getElementById('myVar').setValue(gloabalVar.toString());
app.getElementById("globalVar").setText(gloabalVar);
return app;
}
You can persist data in CacheService (fast but not guaranteed) or ScriptProperties or ScriptDb (a little slower, but persisted) instead of global properties. ScriptDb in particular can hold objects without needing to use strings to store them.

How can I hide a label after few seconds using google apps script?

I have a simple application where the user press a button and a welcome message is shown. I need this message(label) to be hidden after few seconds, say 5 secs.
I couldn't find a function like setTimeout() in google apps script.
Can someone give an idea how I could implement this?
(as you can see, not an experienced programmer).
Thanks!!
A possible solution. The logic is to have two the button click handlers. the 1st one makes the label visible and the 2nd one sleeps 5 seconds and after hides the label.
function doGet(e) {
var app = UiApp.createApplication();
var panel = app.createVerticalPanel();
var btn = app.createButton().setText('Test');
var lblVisible = app.createLabel('Visible Test').setVisible(false).setId('lblVisible');
panel.add(btn);
panel.add(lblVisible);
var handler = app.createServerHandler('onBtnClick');
var handlerWait = app.createServerHandler('onWaitEvent');
handler.addCallbackElement(panel);
handlerWait.addCallbackElement(panel);
btn.addClickHandler(handler);
btn.addClickHandler(handlerWait);
app.add(panel);
return app;
}
function onWaitEvent(e) {
Utilities.sleep(5 * 1000);
var app = UiApp.getActiveApplication();
var lblVisible = app.getElementById('lblVisible');
lblVisible.setVisible(false);
return app;
}
function onBtnClick(e) {
var app = UiApp.getActiveApplication();
var lblVisible = app.getElementById('lblVisible');
lblVisible.setVisible(true);
return app;
}
Progress indicator solution etc, this works. It lets you chain events, I have used it several times.
Updating a widget value on the go. productforums.google.com/d/topic/apps-script/lABoP-cJcGQ/…