Why does close() not do anything? - google-apps-script

Does the app.close() not do anything? it does not appear to work....
// Script-as-app template.
Sample code
function doGet() {
var app = UiApp.createApplication();
var button = app.createButton('Click Me');
var closeButton = app.createButton('Close It');
app.add(closeButton);
app.add(button);
var label = app.createLabel('The button was clicked.')
.setId('statusLabel')
.setVisible(false);
var label2 = app.createLabel('The Close button was clicked.')
.setId('statusLabel2')
.setVisible(false);
app.add(label);
app.add(label2);
var closeHandler = app.createServerHandler('close');
closeHandler.addCallbackElement(label);
var handler = app.createServerHandler('myClickHandler');
handler.addCallbackElement(label);
closeButton.addClickHandler(closeHandler);
button.addClickHandler(handler);
return app;
}
function myClickHandler(e) {
var app = UiApp.getActiveApplication();
var label = app.getElementById('statusLabel');
label.setVisible(true);
app.close();
return app;
}
function close(e)
{
Logger.log("Here");
var app = UiApp.getActiveApplication();
var label2 = app.getElementById('statusLabel2');
label2.setVisible(true);
return app.close();
}
Link to sample code
https://script.google.com/a/macros/scotts.com/s/AKfycbz-avIT3bZNJ68_EpRZYXmh66XLJzYI--F0n7DGNn8jL_wlG1k/exec

As documented here:
"This will only work if the app is being shown as a dialog, such as in
a Google Spreadsheet. It will have no effect when called on an app
that is published as a standalone service."
That's a fundamental limit of browsers, by the way - a page can't close itself.

Related

Adding a ClientHandler like loading bar to a ServerClickHandler

I'm using the code below to run a a function that takes a while to load. My question is, without a lot of modification, is there an easy way of adding something like a clienthandler so that in the midst of running the function it says something along the lines of "Loading...?"
function doGet(e) {
var app = UiApp.createApplication().setTitle('New app');
var grid = app.createGrid(1, 2);
grid.setWidget(0, 0, app.createLabel('First Name + Last Name (Case Sensitive):'));
grid.setWidget(0, 1, app.createTextBox().setName('userName').setId('userName'));
var panel = app.createVerticalPanel();
panel.add(grid);
var buttonPanel = app.createHorizontalPanel();
var button = app.createButton('Submit');
var submitHandler = app.createServerClickHandler('submit')
submitHandler.addCallbackElement(grid);
button.addClickHandler(submitHandler);
buttonPanel.add(button);
var clearButton = app.createButton('Clear');
var clearHandler = app.createServerClickHandler('clear');
clearButton.addClickHandler(clearHandler);
buttonPanel.add(clearButton);
var statusLabel = app.createHTML("").setId('status').setVisible(false);
panel.add(statusLabel);
panel.add(buttonPanel);
app.add(panel);
return app;
};
function clear() {
var app = UiApp.getActiveApplication();
app.getElementById('userName').setValue('');
app.getElementById('status').setVisible(false)
return app;
};
Yes, indeed. That is what client handlers are for.
function doGet(e) {
var app = UiApp.createApplication().setTitle('New app');
var grid = app.createGrid(1, 2);
grid.setWidget(0, 0, app.createLabel('First Name + Last Name (Case Sensitive):'));
grid.setWidget(0, 1, app.createTextBox().setName('userName').setId('userName'));
/* Have the widget ready */
var statusLabel = app.createHTML("").setId('status').setVisible(false);
var panel = app.createVerticalPanel();
panel.add(grid);
var buttonPanel = app.createHorizontalPanel();
var button = app.createButton('Submit');
var submitHandler = app.createServerClickHandler('submit')
submitHandler.addCallbackElement(grid);
button.addClickHandler(submitHandler);
buttonPanel.add(button);
var clearButton = app.createButton('Clear');
var clearHandler = app.createServerClickHandler('clear');
/* Create the client handler */
var plswait = app.createClientHandler().forTargets(statusLabel).setText('Loading...');
clearButton.addClickHandler(clearHandler).addClickHandler(plswait);
buttonPanel.add(clearButton);
panel.add(statusLabel);
panel.add(buttonPanel);
app.add(panel);
return app;
};
function clear() {
var app = UiApp.getActiveApplication();
app.getElementById('userName').setValue('');
app.getElementById('status').setVisible(false).setText('');
return app;
};
It can be more pleasant if you add an image to your status label, here is an example using a transparent animated gif : (simply replace in Srik's code)
var statusLabel = ui.createHorizontalPanel().add(ui.createImage('https://dl.dropboxusercontent.com/u/211279/loading3T.gif'))
.add(ui.createHTML("Loading...")).setId('status').setVisible(false);// Label + animated gif, the text in the HTML widget can be there from the start.
Edit : just noticed something was missing in Srik's code... the clientHandler should go like this :
var plswait = app.createClientHandler().forTargets(statusLabel).setVisible(true);// and eventually setText(' blah blah...') if you didn't define/change it before/elsewhere
Note : now that you have a clientHandler you could also make use of it to setEnabled(false) the button that triggered it to avoid multiple clicks... simply add .forEventSource().setEnabled(false) to your clientHandler.

Image is loaded after the process completion and remains after that

My code is below. It will accept data from the input text; then it will fetch the recent newest feed from stackoverflow(based in the input) in google spreadsheet.
I have(wanted) set an external gif image to be shown as a progress indicator while fetching of rss feed and its processing is going on.
Problem is: When i remove the commented part; that gif image will never be visible to the user and when that is remained as a comment; that gif image is being loaded by the app after the completion of the process and remained then after.
I want it to be visible only when the process(fetching of rss and processing of it) is going on. So is there any way to make it possible?
function stackoverflow(){
var app =UiApp.createApplication().setHeight(380).setWidth(800);
app.setTitle("Enter tag name");
var mydoc=SpreadsheetApp.getActiveSpreadsheet();
var txtBox = app.createTextBox().setFocus(true).setWidth("150").setId("ticker").setName("ticker");
var mainpanel = app.createHorizontalPanel().setId('mainpanel');
mainpanel.add(txtBox);
var subbtn = app.createButton("Get posts!").setId("tick").setWidth("80");
mainpanel.add(subbtn);
var myloadingimg=app.createImage("http://schedule.msu.edu/img/InProgress.gif").setHeight("26").setWidth("26").setId("loadingimg");
mainpanel.add(myloadingimg.setVisible(false));
app.add(mainpanel);
var panel = app.createVerticalPanel().setId('panel');
var submitHandler = app.createServerHandler("clicker").addCallbackElement(mainpanel);
subbtn.addClickHandler(submitHandler);
app.add(panel);
mydoc.show(app);
}
function clicker(e){
var app = UiApp.getActiveApplication();
var txtBox = app.getElementById("ticker");
app.getElementById("loadingimg").setVisible(true);
var panel=app.getElementById("panel");
app.remove(1);
var panel = app.createVerticalPanel().setId('panel');
var stackurl = "http://stackoverflow.com/feeds/tag?tagnames="+e.parameter.ticker+"&sort=newest";
var stackXML = UrlFetchApp.fetch(stackurl).getContentText();
var stackDOC = Xml.parse(stackXML, false);
var stackentry = stackDOC.getElement().getElements('entry');
for (var i = 0; i < stackentry.length; i++) {
var result = stackentry[i];
panel.add(app.createHTML("<br><b>Post Title: </b>"+ result.getElement('title').getText()+"<br>"));
panel.add(app.createAnchor('', '') .setText("Post URL").setHref(result.getElement('link').getAttribute('href').getValue()));
panel.add(app.createHTML("<br>"));
}
var scroll = app.createScrollPanel().setPixelSize(760, 280);
scroll.add(panel);
app.add(scroll);
//app.getElementById("loadingimg").setVisible(false);
return app;
}
function onOpen()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [];
menuEntries.push({name:'stackoverflow',functionName:'stackoverflow'});
ss.addMenu("f2", menuEntries);
}
You can make use of clientHandlers which are meant for precisely such cases.
function stackoverflow(){
...
var clientHandler = app.createClientHandler().forTargets(myloadingimg).setVisible(true);
var submitHandler = app.createServerHandler("clicker").addCallbackElement(mainpanel);
subbtn.addClickHandler(submitHandler).addClickHandler(clientHandler);
...
}
function clicker(e){
var app = UiApp.getActiveApplication();
....
app.getElementById("loadingimg").setVisible(false);
return app;
}

Is it possible to have an static variable in a handler?

I want to make an script that keeps track of the times a button is pressed. It is well known that javascript lacks of support for static vars but this can normally be workaround defining the variable outside of the target function.
Nevertheless this does not work for me on a simple google scripting web application. The code is the following one and it is a simple extension of the template web aplication.
Anyone knows how can this be achieved?
This is the code of the google application:
// Script-as-app template.
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);
myClickHandler.counter = 0;
var handler = app.createServerHandler('myClickHandler');
handler.addCallbackElement(label);
button.addClickHandler(handler);
return app;
}
function myClickHandler(e) {
var app = UiApp.getActiveApplication();
var label = app.getElementById('statusLabel');
label.setVisible(true);
label.setText('Clicked ' + myClickHandler.counter + ' times.')
myClickHandler.counter++;
//app.close();
return app;
}
There are a few possible ways to achieve that, here is one of them using a hidden widget to hold values.
function doGet(){
var app = UiApp.createApplication();
var button = app.createButton('Click Me');
app.add(button);
var counterValue = 0;
var label = app.createLabel('The button was clicked.')
.setId('statusLabel')
.setVisible(false);
var counter = app.createHidden('counter').setId('counter').setValue(counterValue)
app.add(label).add(counter);
var handler = app.createServerHandler('myClickHandler');
handler.addCallbackElement(counter);
button.addClickHandler(handler);
return app;
}
function myClickHandler(e) {
var app = UiApp.getActiveApplication();
var label = app.getElementById('statusLabel');
label.setVisible(true);
var counterValue = Number(e.parameter.counter)
var counter = app.getElementById('counter')
counterValue++;
counter.setValue(counterValue.toString())
label.setText('Clicked ' + counterValue + ' times.')
return app;
}

Cannot read property "parameter" from undefined error with Logger.log

I am getting "TypeError: Cannot read property "parameter" from undefined." when trying to log e.parameter properties. (I inserted the following lines in the contactMe() function)
Logger.log(e.parameter.textBox);
Logger.log(e.parameter);
The script otherwise works fine, any idea?
function doGet() {
var app = UiApp.createApplication();
var mainPanel = app.createVerticalPanel().setId('mainPanel');
app.add(mainPanel);
mainPanel.add(app.createLabel('Enter your email to sign up'));
var form = app.createHorizontalPanel();
mainPanel.add(form);
var email = app.createTextBox().setName('textBox').setId('textBox');
form.add(email);
var button = app.createButton('Sign up');
form.add(button);
var info = app.createLabel().setVisible(true).setId('info');
mainPanel.add(info);
//handler
var handler = app.createServerHandler('contactMe').addCallbackElement(mainPanel);
button.addClickHandler(handler);
return app;
}
function contactMe(e){
var app = UiApp.getActiveApplication();
Logger.log("testing");
Logger.log(e.parameter);
Logger.log(e.parameter.textBox);
app.getElementById('textBox').setValue('').setStyleAttribute("color", "black");
app.getElementById('info').setText('Thank you!').setStyleAttribute("color", "black");
var ss = SpreadsheetApp.openById('0AqKSxC6f0Cc7dF9aT1lUeXFEcnR2eUFYRGs4Y1NiVVE')
.getSheets()[0];
var range = ss.getRange(ss.getLastRow()+1, 1, 1, 2);
var values = [[new Date(),e.parameter.textBox]];
range.setValues(values);
return app;
}
I just tested your exact code (except the sheet stuff) and it works nicely... except that the logger doesn't show anything when called from a handler function but that's a known issue...
I used the label to check the e.parameter value like this :
app.getElementById('info').setText(e.parameter.textBox).setStyleAttribute("color", "black");
A bit out of the box but i think it should work:
function doGet() {
var app = UiApp.createApplication();
var mainPanel = app.createFormPanel;
app.add(mainPanel);
mainPanel.add(app.createLabel('Enter your email to sign up'));
var form = app.createHorizontalPanel();
mainPanel.add(form);
var email = app.createTextBox().setName('textBox').setId('textBox');
form.add(email);
var button = app.createSubmitButton('Sign up');
form.add(button);
var info = app.createLabel().setVisible(true).setId('info');
mainPanel.add(info);
return app;
}
function doPost(e){
var app = UiApp.getActiveApplication();
//Logger wont work in uiApps
//in Form panels the UI is cleared so you want to write a thank you note
app.add(app.createLabel("Thanks"));
var ss = SpreadsheetApp.openById('0AqKSxC6f0Cc7dF9aT1lUeXFEcnR2eUFYRGs4Y1NiVVE')
.getSheets()[0];
var range = ss.getRange(ss.getLastRow()+1, 1, 1, 2);
var values = [[new Date(),e.parameter.textBox]];
range.setValues(values);
return app;
With kind regards,
Thomas van Latum
I just copy pasted your complete code made a spreadsheet and ran it.
It works just perfectly dont forget your } at the end.....

Error encountered: TypeError: Cannot find function getValue in object Generic

I'am very new to google-apps-script. I encounter this error "TypeError: Cannot find function getValue in object Generic" that i can't figure out why.
Here is the code :
function doGet(e) {
var app = UiApp.createApplication();
app.setTitle("My first application");
var vPanel = app.createVerticalPanel();
var hPanel3 = app.createHorizontalPanel();
hPanel3.add(app.createLabel("Text"));
var textArea = app.createTextArea().setId('theText').setName('theText');
//textArea.setName("textArea");
hPanel3.add(textArea);
vPanel.add(hPanel3);
var hPanel4 = app.createHorizontalPanel();
var button = app.createButton("Save");
var handler = app.createServerHandler('onClick');
handler.addCallbackElement(textArea);
button.addClickHandler(handler);
hPanel4.add(button);
vPanel.add(hPanel4);
var label = app.createLabel().setId('label').setText('tata');
//label.setName("label");
var hPanel5 = app.createHorizontalPanel();
hPanel5.add(label);
vPanel.add(hPanel5);
app.add(vPanel);
return app;
}
function onClick(e) {
var app = UiApp.getActiveApplication();
// ERROR occurs here when the button is clicked
var text = app.getElementById('theText').getValue();
Logger.log(text);
app.getElementById('label').setValue(e.parameter.textArea + ' toto');
//label.setText(textArea.getValue());
return app;
}
I've already change the name and id of the textArea but nothing works.
Thanks for your help!
Trung
The TextArea class has no the getValue method. Its value is passed to a handler as a parameter. Here is a sample demonstrating how it works.
function doGet(e) {
var app = UiApp.createApplication();
var panel = app.createFlexTable();
panel.setWidth('100%');
var btn = app.createButton().setId('btn').setText('Click Me');
var textArea = app.createTextArea().setName('textArea').setValue('Text');
var handler = app.createServerHandler('onBtnClick');
handler.addCallbackElement(panel);
btn.addClickHandler(handler);
panel.setWidget(0, 0, btn);
panel.setWidget(1, 0, textArea);
app.add(panel);
return app;
}
function onBtnClick(e) {
var app = UiApp.getActiveApplication();
var btn = app.getElementById('btn');
var textAreaValue = e.parameter.textArea;
btn.setText(textAreaValue);
return app;
}
Change
var text = app.getElementById('theText').getValue();
by
var text = e.parameter.theText;
e is your form value
you use the name fixed with setName to choose which parameter of e you want to get in the variable
If you refer to the documentation for textArea, there is no such method as getValue() for textArea. As Cartman answered you can get the value through the callbackElement which uses the name of the textArea as parameter (the ID is not necessary unless you want to setValue() with something else)