Automatically close a Google Apps Script UiApp after five seconds - google-apps-script

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.

Related

Google Apps Script - Share widgets between functions

This is my first time working with Google apps scripts, and I'm a bit confused as to how to access widgets from multiple functions.
Basically, I'd like to have a button that updates a label widget. So the label has some default text, but then updates to show some other text after an 'Update' button is pressed.
From what I've read, the only things that can be passed into event handlers are objects with a setName method. A label widget doesn't have this, so what can I do to update the value of a widget in my doGet function from the other handler function?
Here is an idea of what I'd like to do (but can't get to work):
function doGet() {
var app = UiApp.createApplication();
// Create the label
var myLabel = app.createLabel('this is my label')
app.add(myLabel)
// Create the update button
var updateButton = app.createButton('Update Label');
app.add(updateButton)
// Assign the update button handler
var updateButtonHandler = app.createServerHandler('updateValues');
updateButton.addClickHandler(updateButtonHandler);
return app;
}
function updateValues() {
var app = UiApp.getActiveApplication();
// Update the label
app.myLabel.setLabel('This is my updated label')
return app;
}
I've been scouring the internet for hours trying to find a solution but can't seem to figure it out. Any suggestions?
What you mention about getting the value of a widget from an object name property is to GET the value of a widget, not to SET it. (in this case uppercase is not to "shout" but simply to get attention :-))
And the example of the Label is typically an example of a widget that you cannot read the value...
What you are looking for is a way to set widget value : you have to get the element by its ID : see example below in your updated code:
function doGet() {
var app = UiApp.createApplication();
// Create the label
var myLabel = app.createLabel('this is my label').setId('label');
app.add(myLabel)
// Create the update button
var updateButton = app.createButton('Update Label');
app.add(updateButton)
// Assign the update button handler
var updateButtonHandler = app.createServerHandler('updateValues');
updateButton.addClickHandler(updateButtonHandler);
return app;
}
function updateValues() {
var app = UiApp.getActiveApplication();
// Update the label
var label = app.getElementById('label').setText('This is my updated label');
return app;
}

Listbox not opening handler

I am trying to create a menu in a listbox format where user chooses an option and then another uiapp is shown with the info they selected. I am having an issue here that when I opened google gives me an error that says Error encountered. An expected error occurred. I think it has to do with the setId part, if I remove one of the setId's the error doesnt happen. is this even possible?
function doGet(e) {
var app = UiApp.createApplication().setTitle("Services");
var dropDownList = app.createListBox().setName('list').setId('list');
var infoLabel = app.createLabel('Scroll around to select the service desired').setId('infoLabel');
var panel = app.createVerticalPanel();
//addItem fills the list
dropDownList.addItem("Option 1").setId("add");
dropDownList.addItem("Option 2");
panel.add(dropDownList);
panel.add(infoLabel);
app.add(panel);
var info = app.getElementById("add");
var handler2 = app.createServerHandler('display2');
info.addClickHandler(handler2);
app.add(dropDownList);
app.add(infoLabel);
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
spreadsheet.show(app);
}
function display2(e) {
var app = UiApp.createApplication();
var html = app.add(app.createHTML("<p><p><b>You have selected this option</b> </p>")).setHeight(220).setWidth(220);
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
spreadsheet.show(app);
return app;
}
Are you deploying this as a web app or a script within a Spreadsheet?
If you are deploying this as a web app, then SpreadsheetApp.getActiveSpreadsheet() will not work - replace it with SpreadsheetApp.openById(id) where id is your spreadsheet ID which you will find in the URL when you open the file in the browser.
If you want to deploy this w/in a spreadsheet through a menu item or a simple button, then that works as is.
I was able to just copy paste your code and get the listbox part working fine -
https://docs.google.com/spreadsheet/ccc?key=0AkJNj_IM2wiPdHRYQThlaGVVSk04R052ZGNqclhEZWc#gid=0
Update -
I now understand what you are trying to do. Couple of things - you want to make sure you are adding a callback element via handler.addCallbackElement(myWidget) otherwise, you will not be able to read the value of the element. Second thing is that you don't need a server handler on each option in a dropdown list. Just having one handler will fire it for every change and you'll be able to get the option you selected.
I've cleaned up the code here below and also updated the spreadsheet to use this code.
function showUI() {
var app = UiApp.createApplication().setTitle("GeekSquad Services");
var infoLabel = app.createLabel('Scroll around to select the service desired');
var dropDownList = app.createListBox().setName('list').setId('list');
dropDownList.addItem("Option 1");
dropDownList.addItem("Option 2");
//you can add as many options here manually or dynamically
var handler = app.createServerHandler('dropDownCallback')
handler.addCallbackElement(dropDownList);
dropDownList.addClickHandler(handler);
var panel = app.createVerticalPanel();
panel.add(dropDownList);
panel.add(infoLabel);
app.add(panel);
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
spreadsheet.show(app);
}
function dropDownCallback(e) {
var app = UiApp.createApplication();
var html = app.add(app.createHTML("<b>You have selected this option</b> " + e.parameter.list));
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
spreadsheet.show(app);
}
Update #2 -
If you want to fork off and create different app instances thats easy (though its unclear why wouldn't just change panels).
function dropDownCallback(e) {
if(e.parameter.list === 'Option 1'){
var app = UiApp.createApplication();
var html = app.add(app.createHTML("Here for option!"));
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
spreadsheet.show(app);
}
else if (e.parameter.list ==== 'Option 2'){
//create and show other App here or whatever else
}
//refactor this better to not repeat code.
}

How do events work in Google Script in regards to getting data from elements

Question 1) When a button is clicked is it possible to use something like this (see code below)?
function Submit(e) {
var app = UiApp.getActiveApplication();
var checked = app.getElementById("checkbox").getValue();
}
Question 2) When a label is clicked is it possible to use something like this (see code below)?
function LabelClick(e) {
var LabelText = e.parameter.getText();
}
Sorry, this probably stupid, but I can't see to find any decent examples of this and can't seem to work this out from Google's documentation and I'm just getting used to google script too. If you have the answer I would really appreciate it.
you are not very far... but not close enough to get it working...
Ui element's value is sent to the handler function in a so called callbackelement that is added to the handler. This callbackelement may be a button, a label or, more easily, the parent widget that contains all the other widgets. These "elements" are in the "e" of the handler function and are identified by their names.
In the other direction, ie if you need to modify an Ui element from another function then you can get this element by its ID (getElementbyId()) and assign it a value just the same way as you'd do it in the UI definition function.
I copy/paste a sample code from another post to illustrate what I said, you can see the e.parameter.chkmode that holds the value of the checkBox and I'll add a Label to show the reverse process (the text is changed when the button is clicked).
Hoping I was clear enough,
var sh = SpreadsheetApp.getActiveSheet();
var ss = SpreadsheetApp.getActiveSpreadsheet();
//
function move() {
var app = UiApp.createApplication().setTitle("move test")
.setHeight(100).setWidth(400).setStyleAttribute("background-color","beige");
var panel = app.createVerticalPanel();
var next = app.createButton('next').setWidth('180');
var chkmode = app.createCheckBox("moving mode (checked = up/dwn, unchecked=L/R)").setValue(false).setName('chkmode');
var label = app.createLabel("test Label with text that will be modified on click").setId('label');
panel.add(next).add(chkmode).add(label);
var handler = app.createServerHandler('click').addCallbackElement(panel);
next.addClickHandler(handler);
app.add(panel);
ss.show(app);
}
//
function click(e) {
var app = UiApp.getActiveApplication();
var activeline = sh.getActiveRange().getRow();// get the row number of the selected cell/range
var activecol = sh.getActiveRange().getColumn();// get the row number of the selected cell/range
var label = app.getElementById('label');
label.setText('You have clicked the button');
var chkmode=e.parameter.chkmode;
if(chkmode=="true"){
activeline++
}else{
activecol++}
var sel=sh.getRange(activeline,activecol);
sh.setActiveSelection(sel);// make the next row active
return app;
}
For a UI and events tutorial, I recommend:
https://developers.google.com/apps-script/uiapp

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/…

Unable to use list box with server handler to change text of label

If the title is confusing, hopefully this makes it more clear what I'm trying to do:
function doGet(e) {
var app = UiApp.createApplication();
var list = app.createListBox().setName('list');
list.addItem("this");
list.addItem("that");
list.addItem("they");
var handler = app.createServerHandler('foo').addCallbackElement(list);
list.addChangeHandler(handler);
var label = app.createLabel("test").setId('label');
var panel = app.createVerticalPanel();
panel.add(list);
panel.add(label);
app.add(panel);
return app;
}​
function foo(e) {
var app = UiApp.getActiveApplication();
var value = e.parameter.list;
var label = app.getElementById('label');
label.setText(value);
}
It doesn't call any errors. If I intentionally put an error in foo, I get an error message, so I'm assuming the handler is getting called and just isn't doing anything. This works in a spreadsheet if I just have it bring up a Browser.msgBox(value), so I know that much works.
I'm trying to use this in a program that will automatically update all the listboxes on the page based on what is selected in the first listbox. I've been able to change things like visibility using server handlers and app.getElementById, but only with radio buttons, not a list box. I'm clearly doing something wrong here, but it's not obvious what that is.
To have your changes to the UiApp updated you have to return the app on your handler, e.g.
//...
label.setText(value);
return app;
}