Message Box in popup form - google-apps-script

I have a doubt,
I make a Button for Submit form and when I press the first button appear to me a message of confirmation to continue or not, but when I press "no" and the message disappear and return to form,but the first button doesn't work more.
You known that I make wrong.
thanks for all.
function doGet(){
var app = UiApp.createApplication().setTitle('Request Form');
var flow = app.createFlowPanel().setStyleAttribute("textAlign", "center").setWidth("900px");
var buttons = app.createButton('Print and Save').setId('buttons');
var handlers = app.createServerClickHandler('question').addCallbackElement(flow);
buttons.addClickHandler(handlers);
flow.add(buttons);
app.add(flow);
return app;
}
function question(e){
var app = UiApp.getActiveApplication();
var dialog = app.createPopupPanel().setModal(true).setSize(700, 100).setPopupPosition(10, 400);
var closeHandler = app.createClientHandler().forTargets(dialog).setVisible(false);
var handlersend = app.createServerClickHandler('Send');
var handleract =app.createServerClickHandler('activateAgain');
var labelp = app.createLabel('Are you sure that this information is correct?')
var buttonp1= app.createButton('yes, continue').addClickHandler(closeHandler).addClickHandler(handlersend);
var buttonp2= app.createButton('No, I want correct').addClickHandler(closeHandler).addClickHandler(handleract);
app.getElementById('buttons').setEnabled(false);
var gridp = app.createGrid(1,5);
gridp.setWidget(0, 0, labelp)
.setWidget(0,1,buttonp1)
.setWidget(0,2,buttonp2);
dialog.add(gridp)
dialog.show();
return app;
}
function activateAgain(e){
var app = UiApp.getActiveApplication();
app.getElementById('buttons').setEnabled(true);
return app;
}
function Send(e){
}

You are trying to make it happen in clientHandler which is basically a good idea but the problem is that some methods are not available in clientHandlers, for example hide() is not !
So you used setVisible(false) to hide the dialog but then you can't get it visible again easily...
All in all, I found it was easier with serverHandler and a few modifications.
Since you seem to be quite comfortable with UiApp I don't need to explain further, the code is self explanatory enough (I hope :-)
Code below : (and test HERE)
function doGet(){
var app = UiApp.createApplication().setTitle('Request Form');
var flow = app.createFlowPanel().setStyleAttribute("textAlign", "center").setWidth("900px");
var buttons = app.createButton('Print and Save').setId('buttons');
var handlers = app.createServerClickHandler('question').addCallbackElement(flow);
buttons.addClickHandler(handlers);
flow.add(buttons);
app.add(flow);
return app;
}
function question(e){
var app = UiApp.getActiveApplication();
var dialog = app.createPopupPanel().setModal(true).setSize(700, 100).setPopupPosition(10, 400).setId('dialog');
var button = app.getElementById('buttons').setEnabled(true);
var closeHandler = app.createClientHandler().forTargets(button).setEnabled(true);
var correctHandler = app.createServerHandler('hideDialog');
var handlersend = app.createServerClickHandler('Send');
var labelp = app.createLabel('Are you sure that this information is correct?')
var buttonp1= app.createButton('yes, continue').addClickHandler(handlersend);
var buttonp2= app.createButton('No, I want correct').addClickHandler(closeHandler).addClickHandler(correctHandler);
app.getElementById('buttons').setEnabled(false);
var gridp = app.createGrid(1,5);
gridp.setWidget(0, 0, labelp)
.setWidget(0,1,buttonp1)
.setWidget(0,2,buttonp2);
dialog.add(gridp)
dialog.show();
return app;
}
function hideDialog(){
var app = UiApp.getActiveApplication();
var dialog = app.getElementById('dialog');
dialog.hide();
return app;
}
function Send(e){
var app = UiApp.getActiveApplication();
var dialog = app.getElementById('dialog');
dialog.hide();
app.getElementById('buttons').setEnabled(false);
app.add(app.createLabel('send'));
return app;
}

Related

Changing a Textbox to a Button in Google Script

I'm working on a todo list program in google script. I have it so that people can type in their task in a textbox, but I want it so that once they hit the enter key, the textbox turns into a button that, that says what the task is, and they will later press when they finished that task and it will return to a textbox. I can't figure out how to make any changes to the app from inside another function.
What I have so far is:
function doGet(e) {
var app = UiApp.createApplication();
var panel = app.createAbsolutePanel().setHeight("750px").setWidth("1600px");
var button = app.createButton("swag");
var enterHandler = app.createServerKeyHandler('enterPress');
enterHandler.addCallbackElement(panel);
var box = app.createTextBox().addKeyUpHandler(enterHandler);
panel.add(box,0,0);
app.add(panel);
return app;
}
function enterPress(e){
var app = UiApp.getActiveApplication();
if (e.parameter.keyCode==13){
var button2 =app.createButton('swag');
var panel = app.createAbsolutePanel().setHeight('750px').setWidth('1600px');
panel.add(button2,0,0);
app.add(panel);
}
return app;
}
It recognizes the enter press, but the changes won't return to the main app.
You can do it like this :
note : I didn't "place" the button, I guess you have an idea on how you want them to show up...
You could also use a grid to place them... as you want.
function doGet(e) {
var app = UiApp.createApplication();
var panel = app.createAbsolutePanel().setHeight("750px").setWidth("1600px");
var enterHandler = app.createServerKeyHandler('enterPress').addCallbackElement(panel);
var button = app.createButton("confirm",enterHandler).setId('swag');
var tBox = app.createTextBox().setName('tBox').setId('tBox').setWidth(300).setStyleAttributes({'textAlign':'center'});
var bBox = app.createButton("no Text",enterHandler).setVisible(false).setId('bBox').setWidth(300);
panel.add(tBox,20,20).add(bBox,20,20).add(button,140,50);
app.add(panel);
return app;
}
function enterPress(e){
var app = UiApp.getActiveApplication();
if (e.parameter.source=='bBox'){
app.getElementById('bBox').setVisible(false);
app.getElementById('tBox').setVisible(true);
}
if (e.parameter.source=='swag'){
app.getElementById('bBox').setVisible(true).setHTML(e.parameter.tBox);
app.getElementById('tBox').setVisible(false);
}
return app;
}
Test here
Edit: code modified with placement .
EDIT2 : You could also hide the enter button, I find it nicer.
function enterPress(e){
var app = UiApp.getActiveApplication();
if (e.parameter.source=='bBox'){
app.getElementById('bBox').setVisible(false);
app.getElementById('tBox').setVisible(true);
app.getElementById('swag').setVisible(true);
}
if (e.parameter.source=='swag'){
app.getElementById('bBox').setVisible(true).setHTML(e.parameter.tBox);
app.getElementById('tBox').setVisible(false);
app.getElementById('swag').setVisible(false);
}
return app;
}

use return app; without ending current function

Is there another way to update the gui than return app;?
I want to set the text on a label before doing an url fetch, like started downloading, and after it completes turn the label into download complete.
function EventHandler(e) {
var app = UiApp.getActiveApplication();
var url = e.parameter.URLInput;
var label = app.getElementById("label");
label.setText("Download started");
try{
var file = UrlFetchApp.fetch(url).getBlob();
} catch(err){
label.setText(err);
}
label.setText("Download finished");
return app;
}
The label stays empty until UrlFetchApp is completed, and then the label's content is 'Download finished'. Adding return app; before the fetch ends the function.
You have to use a clientHandler to set Text to your label in the doGet function, the clientHandler executes immediately when you click the button.
Here is a test app that shows how it works: (online test available here with simulated download)
function doGet(){
var app = UiApp.createApplication();
var label = app.createLabel('---empty---').setId('label');
app.add(label)
var handler = app.createServerHandler('EventHandler');
var cHandler = app.createClientHandler().forTargets(label).setText('starting download');
var btn = app.createButton('start',handler).addClickHandler(cHandler);
app.add(btn);
return app;
}
function EventHandler(e) {
var app = UiApp.getActiveApplication();
var url = e.parameter.URLInput;
var ulabel = app.getElementById("label");
ulabel.setText("Download started");
try{
//var file = UrlFetchApp.fetch(url).getBlob();
} catch(err){
label.setText(err);
}
ulabel.setText("Download finished");
return app;
}
note : you can use the same client handler to do lots of other usefull things : disable the button, show a spinner... whatever you like that must happen in the doGet function without delay.
EDIT following your comment
Have you tried using 2 server handlers in parallel ? in the displayHandler you could setup any condition you want, I left it simple in the following example :
function doGet(){
var app = UiApp.createApplication();
var label = app.createLabel('---empty---').setId('label');
app.add(label)
var handler = app.createServerHandler('EventHandler');
var displayHandler = app.createServerHandler('displayHandler');
var btn = app.createButton('start',handler).addClickHandler(displayHandler);
// you can add other handlers (keypress, hover... whatever) they will all execute at the same time
app.add(btn);
return app;
}
function displayHandler(e) {
var app = UiApp.getActiveApplication();
var ulabel = app.getElementById("label");
ulabel.setText("Download started");
return app;
}
function EventHandler(e) {
var app = UiApp.getActiveApplication();
var url = e.parameter.URLInput;
var ulabel = app.getElementById("label");
try{
Utilities.sleep(2000);// simulating download
} catch(err){
label.setText(err);
}
ulabel.setText("Download finished");
return app;
}

setPopupPosition not working

I have the following code that basically works, but the dialog box is not located where the setPopupPosition method says it should be. I am testing this on Chrome.
function doGet() {
var member1 = "Member1";
var member2 = "Member2";
var app = UiApp.createApplication();
var vPanel = app.createVerticalPanel().setId('vPanel').setSpacing(10);
var hPanel = app.createHorizontalPanel().setId('hPanel').setSpacing(10);
var msg = app.createHTML("Which member's information do you want to update?");
var radio1 = app.createRadioButton('rb1').setText(member1);
var radio2 = app.createRadioButton('rb2').setText(member2);
var selectBtn = app.createButton("Select").setStyleAttribute("margin-left", "80px").setFocus(true);
var cnclBtn = app.createButton("Cancel");
var dlg = app.createDialogBox()
.setModal(true)
.setText("Select Member")
.setTitle("Select Member")
.setPopupPosition(200, 200); //PopupPosition does not work
hPanel.add(selectBtn)
.add(cnclBtn);
vPanel.add(msg)
.add(radio1)
.add(radio2)
.add(hPanel);
dlg.add(vPanel);
dlg.show();
app.add(dlg);
return app;
}
It seems that setPopupPosition works only when the popup is created in a handler function.... I know it seems weird but in a couple of script I wrote I use it without issue in handler and it doesn't work if I copy/paste it in a doGet function....
Anyway, I don't know how you're going to use it in your real code but in the mean time you could position it with style attributes...
This code works :
function doGet() {
var member1 = "Member1";
var member2 = "Member2";
var app = UiApp.createApplication();
var vPanel = app.createVerticalPanel().setId('vPanel').setSpacing(10);
var hPanel = app.createHorizontalPanel().setId('hPanel').setSpacing(10);
var msg = app.createHTML("Which member's information do you want to update?");
var radio1 = app.createRadioButton('rb1').setText(member1);
var radio2 = app.createRadioButton('rb2').setText(member2);
var selectBtn = app.createButton("Select").setStyleAttribute("margin-left", "80px").setFocus(true);
var cnclBtn = app.createButton("Cancel");
var dlg = app.createDialogBox()
.setModal(true)
.setText("Select Member")
.setTitle("Select Member")
.setStyleAttributes({'margin-top':200,'margin-left':200})
.setPopupPosition(200, 200); //PopupPosition does not work
hPanel.add(selectBtn)
.add(cnclBtn);
vPanel.add(msg)
.add(radio1)
.add(radio2)
.add(hPanel);
dlg.add(vPanel);
dlg.show();
app.add(dlg);
return app;
}
btw, your radioButtons won't work as it is, they must have the same name to behave as they are supposed to. There is an open issue on that subject and a couple of workaround as well. (issue 506)

How To Allow Users to Review Answers before Submiting Form?

I've built a form with UiApp to collect information from the user. It's rather complex with multiple panels and file uploads, so I would like to give the user the opportunity review their inputs before submitting. I was hoping to display their inputs on one final review panel that would then allow them to decide to edit the info and move back to a earlier panel to edit.
Following is the test script. The farthest I've gotten is getting it to return 'textBox' and not the value of the textBox. Is it possible to get the values while staying in the doGet portion of my script, or must I move to doPost to access the values?
What would be the work around you would suggest?
Thanks for any and all help!
function doGet(e){
var app = UiApp.createApplication();
var appPanel = app.createVerticalPanel();
var form = app.createFormPanel();
var panel1 = app.createHorizontalPanel();
var emailLabel = app.createLabel('Your Email');
var email = app.createTextBox().setName('email').setId('email');
app.add(form);
var button1 = app.createButton('Go to Review');
panel1.add(emailLabel);
panel1.add(email);
panel1.add(button1);
appPanel.add(panel1);
form.add(appPanel);
var panel2 = app.createHorizontalPanel().setVisible(false);
var reviewLabel = app.createLabel('Your Email:');
var reviewEmail = app.createLabel(email);
panel2.add(reviewLabel);
panel2.add(reviewEmail);
appPanel.add(panel2);
//
var reviewPageTwo = app.createClientHandler()
.forTargets(panel1).setVisible(false)
.forTargets(panel2).setVisible(true);
button1.addClickHandler(reviewPageTwo);
return app;
}
UPDATE 8.24.12
I'm including the resulting script. It includes the review function, the button to lead the user back to edit, and the submitButton to post it. (You will need to replace the spreadsheet ID for the post to work.)
Thank for the help all!
Martin
function doGet(e){
var app = UiApp.createApplication();
var appPanel = app.createVerticalPanel();
var form = app.createFormPanel();
var panel1 = app.createHorizontalPanel().setId('panel1');
var emailLabel = app.createLabel('Your Email');
var email = app.createTextBox().setName('email').setId('email');
var syncChangeHandler = app.createServerHandler('syncText').addCallbackElement(form);
app.add(form);
var button1 = app.createButton('Go to Review');
panel1.add(emailLabel);
panel1.add(email);
panel1.add(button1);
appPanel.add(panel1);
form.add(appPanel);
var panel2 = app.createHorizontalPanel().setId('panel2').setVisible(false);
var reviewGrid = app.createGrid(3,3).setId('reviewGrid');
var reviewEmail = app.createLabel().setId('reviewEmail');
var reviewLabel = app.createLabel('Your Email:');
var submitButton = app.createSubmitButton('Submit');
var button2 = app.createButton('Edit Response');
panel2.add(reviewLabel);
panel2.add(reviewEmail);
panel2.add(button2);
panel2.add(submitButton);
appPanel.add(panel2);
//
var editResponse = app.createClientHandler()
.forTargets(panel1).setVisible(true)
.forTargets(panel2).setVisible(false);
button1.addClickHandler(syncChangeHandler);
button2.addClickHandler(editResponse);
return app;
}
function syncChangeHandler(e){
var app = UiApp.getActiveApplication();
app.getElementById('reviewEmail').setText(e.parameter.email);
app.getElementById('panel1').setVisible(false);
app.getElementById('panel2').setVisible(true);
return app;
}
function doPost(e){
var ss = SpreadsheetApp.openById('*your spreadsheet id here*').getSheets()[0];
var range = ss.getRange(ss.getLastRow()+1, 1, 1,2);
var values = [[new Date(),e.parameter.email]];
range.setValues(values);
var app = UiApp.getActiveApplication();
var label = app.createLabel('Thank You!');
app.add(label);
return app;
}
You have your entire function inside doGet(). The doGet() function is executed when your UI is first loaded.
So,
var email = app.createTextBox().setName('email').setId('email');
actually resolves to a text box. When you do
var reviewEmail = app.createLabel(email);
you are trying to pass a text box as an argument to createLabel, which is not allowed. Therefore this won't work. You must handle the changes to the text box in a handler.
function doGet(){
var syncChangeHandler = app.createServerHandler('syncText').addCallbackElement(form);
var email = app.createTextBox().setName('email').setId('email');
...
var reviewEmail = app.createLabel().setId('reviewEmail');
...
}
function syncText(e){
var app = UiApp.getActiveAplication();
app.getElementById('reviewEmail').setText(e.parameter.email);
return app;
}
What Srik said is true (of course ;-)), you can't indeed assign a label this type of value... What I would do (since you work in a doGet/doPost structure) is to create a second button just aside of the submit button that triggers a handler to a 'review' function that populates all the corresponding textBoxes , listBoxes or whatever you have with the values coming from your main form (a sort of copy of it) in the review panel that you already have. To achieve this you will need to add the form as a callBackElement to the handler (which was not necessary with the doPost scheme).
Another option could be to add this handler to all the widgets separately with 'key up' triggers or 'Value change triggers' so that the review panel is always up to date in real time, in this case the 'review before submit panel' could be visible at any time without further action from the user other than make it eventually visible (although it could also be always visible). In this option the handler function would be more like a 'synchroniser'. I'm afraid you'll have some difficulties with file upload though (since this can only work in a doGet/doPost structure).

How to know which Radio Button is selected?

I have 3 Radio buttons in my Ui in the same Radio group. They are,
var rbutton1 = app.createRadioButton('dist','5 miles');
var rbutton2 = app.createRadioButton('dist','10 miles');
var rbutton3 = app.createRadioButton('dist','25 miles');
In the event handler function, the variable, e.parameter.dist gives true or false just based on whether rbutton3 (the last radio button) is checked or not. Is there any way to determine what radio button is selected exactly?
The only way the make radio buttons group work like this (as intended by design) is by using them in a FormPanel and looking the name (in your case "dist") on a doPost from a submit action of the form.
There's some workarounds though, using the new client handlers that make it radio buttons usage on any panel roughly the same as on the from. Please take a look at this issue on the tracker. You may want to star this issue as well, to keep track of updates and kind of vote for it.
I use:
eventData.parameter.source
and pick up the change using addClickHandler.
You need to store this somewhere
Are these buttons suppose to be in an exclusive OR mode. If so, they need to have the same name. Look at Serge's answer for a detailed explanation and example code.
in the meantime I came up with a workaround to set the radiobutton as well, in this example I use a listBox but any other data could be used.
Here is the complete code : (to test in a spreadsheet container)
function radiotest() {
var app = UiApp.createApplication();
var panel = app.createVerticalPanel();
var radioValue = app.createTextBox().setId('radioValue');
radioValue.setId("radioValue").setName("radioValue");
var listhandler = app.createServerHandler('listhandler').addCallbackElement(panel);
var list = app.createListBox().addChangeHandler(listhandler).setName('list');
for(var i = 1; i < 10; i++){
var name = 'choice '+i;
list.addItem('Activate '+name,name)
var handler = app.createClientHandler().forTargets(radioValue).setText(name);
panel.add(app.createRadioButton('radioButtonGroup',name).addValueChangeHandler(handler).setId(name));
}
panel.add(radioValue);
var getit=app.createButton("Valide").setId("val");
panel.add(getit).add(list)
var handler = app.createServerHandler("valide")
handler.addCallbackElement(panel)
getit.addClickHandler(handler);
app.add(panel);
SpreadsheetApp.getActiveSpreadsheet().show(app);// show app
}
//
function valide(e){ ;// This function is called when key "validate" is pressed
var sh = SpreadsheetApp.getActiveSheet();
var RadioButton = e.parameter.radioValue;
sh.getRange('A1').setValue(RadioButton);
var app = UiApp.getActiveApplication();
return app;
}​
function listhandler(e){ ;// This function is called when listBox is changed
var sh = SpreadsheetApp.getActiveSheet();
var app = UiApp.getActiveApplication();
var listvalue = e.parameter.list
var radioValue = app.getElementById('radioValue').setValue(listvalue)
sh.getRange('A2').setValue(listvalue);
var radiobutton = app.getElementById(listvalue)
radiobutton.setValue(true)
return app;
}​
the selected radioButton values comes in the textBox value and the listBox allows to select which radioButton is activated... it shows up like this
There is also another approach, as stated by eddyparkinson that is to use the e.parameter.source but this works only if the handler is assigned directly to the radioButton and not using a 'submit' button. In many case it can be used and makes the code a(little) bit lighter.
Here is a test of this code
function radiotest2() {
var app = UiApp.createApplication();
var panel = app.createVerticalPanel();
var listhandler = app.createServerHandler('listhandler2').addCallbackElement(panel);
var list = app.createListBox().addChangeHandler(listhandler).setName('list');
var handler = app.createServerHandler("valide2")
handler.addCallbackElement(panel)
for(var i = 1; i < 10; i++){
var name = 'choice '+i;
list.addItem('Activate '+name,name)
panel.add(app.createRadioButton('radioButtonGroup',name).setId(name).addClickHandler(handler));
}
panel.add(list)
app.add(panel);
SpreadsheetApp.getActiveSpreadsheet().show(app);// show app
}
function valide2(e){ ;// This function is called when a radioButton is selected
var sh = SpreadsheetApp.getActiveSheet();
var source = e.parameter.source;
var radioValue = '';
if(source.match('choice')=='choice'){radioValue=source}
sh.getRange('A1').setValue(radioValue);
var app = UiApp.getActiveApplication();
return app;
}​
function listhandler2(e){ ;// This function is called when listBox is changed
var sh = SpreadsheetApp.getActiveSheet();
var app = UiApp.getActiveApplication();
var listvalue = e.parameter.list
sh.getRange('A2').setValue(listvalue);
var radiobutton = app.getElementById(listvalue)
radiobutton.setValue(true)
return app;
}​