doPost Twice in Google Apps Script? - 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'));

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;
}

Convert ModalDialog to DialogBox

In my apps script for Google Docs I'm trying to convert a ModalDialog to a DialogBox so that I can take advantage of the addCloseHandler() on DialogBoxes.
My showModalDialog works with the following GS code:
function showSheetPicker() {
var html = HtmlService.createTemplateFromFile('sheetPicker').evaluate().
setHeight(400).setWidth(600);
DocumentApp.getUi().showModalDialog(html, "Select a Sheet");
}
However, when I tried converting that to use createDialogBox(), I came up with the following:
function showSheetPicker() {
var app = UiApp.createApplication();
var autoHide = false;
var modal = true;
var dialog = app.createDialogBox(autoHide, modal);
dialog.setPopupPosition(100, 100).setSize(650, 450).setHTML(html)
.setTitle("Select a Sheet").createCloseHandler(handlingTheClose).show();
return app;
}
This is producing an error that tells me: The script completed but the returned value is not a supported return type..
What would I need to do to convert my ModalDialog to a DialogBox so that I can take advantage of the addCloseHandler()?
This is an example of a doc showing a dialogBox but the result is quite disappointing...
function myFunction() {
var app = UiApp.createApplication();
var autoHide = false;
var modal = true;
var dialog = app.createDialogBox(autoHide, modal);
dialog.setPopupPosition(100, 100).setSize(650, 450)
.setTitle('hover me').setHTML('this is a test dialog');
app.add(dialog).setHeight(450).setWidth(650);
DocumentApp.getUi().showModelessDialog(app, "Select a Sheet")
}
I've never succeeded in using this widget... good luck.
As for the closeHandler, I doubt you can use it since you won't be able to close the inner dialogBox, you will actually close the ModelessDialog in this example... (good luck again... I give up ;-)

personalizing google app script ui for example with css

I have some google script code in a spreadsheet like this:
function doGet(e) {
var app = UiApp.createApplication();
//////////////////////////////////////////////////////////
var buttonEntrata = app.createButton('Entrata');
app.add(buttonEntrata);
var labelEntrata = app.createLabel('Entrata!')
.setId('statusLabelEntrata')
.setVisible(false);
app.add(labelEntrata);
var handlerEntrata = app.createServerHandler('myClickHandlerEntrata');
buttonEntrata.addClickHandler(handlerEntrata);
/////////////////////////////////////////////////////////////
var buttonUscita = app.createButton('Uscita');
app.add(buttonUscita);
var labelUscita = app.createLabel('Uscita!')
.setId('statusLabelUscita')
.setVisible(false);
app.add(labelUscita);
var handlerUscita = app.createServerHandler('myClickHandlerUscita');
buttonUscita.addClickHandler(handlerUscita);
return app;
}
function myClickHandlerEntrata(e) {
var app = UiApp.getActiveApplication();
var labelEntrata = app.getElementById('statusLabelEntrata');
labelEntrata.setVisible(true);
entrata()
app.close();
return app;
}
function myClickHandlerUscita(e) {
var app = UiApp.getActiveApplication();
var labelUscita = app.getElementById('statusLabelUscita');
labelUscita.setVisible(true);
uscita()
app.close();
return app;
}
This creates me 2 buttons that do what they have to.
the problem is that when I call the page like this:
https://script.google.com/macros/s/example_example_example_example/dev
I get a really ugly page which id like to personalize, for example aligning the buttons in the center of the page, resizing them maybe dynamically based on the screen resolution, etc....
how can I do this since this is a script and not an html page?
does google script support something like css?
TNX :)
There are a lot of CSS equivalents (attributes have the same name but are written differently, using camelCase and no hyphens)that you can use in UiApp, the full list is here.
You can use it with setAttribute(key,value) or setAttributes({key:value,key:value}) , the second one allowing for any number of parameters, doc here.
UiApp has been deprecated. Try HTMLService Instead.
Example:
function doGet(){
var html=HtmlService.createHtmlOutputFromFile("name_of_html_file");
html.setTitle("Some_Title");
return html;
}
Note: When you give link to others, deploy and give the URL that ends with "/exec".
URL that ends with /dev is that only the owner of the app can use!

Google Apps Script Persistence

Background: I have a google site and I have been pulling information from a google spreadsheet containing the marks of my students, however I'd like to make it more dynamic so that they can request a report of all of their current marks whenever they'd like. In the script that I've written, students will enter a password, click a button and then their marks will be generated.
Issue: From what I've read, when they click the button, the handler for the button causes the script to be re-run. The current spreadsheet cannot be stored and when I try to access the spreadsheet, it tells me that it is null. How can I get access to the spreadsheet again? I've tried using ScriptProperties, but I got the same result. By the way, it works if I do not try to run it as a webapp.
Here's the doGet() function and part of the getPassword() function that is called once the button on the UI is pressed.
function doGet() {
var app = UiApp.createApplication();
app.add(app.loadComponent("MyGui"));
var panel = app.getElementById("VerticalPanel1");
var text = app.createPasswordTextBox().setName("text");
var handler = app.createServerHandler("getResults").addCallbackElement(text);
panel.add(text);
panel.add(app.createButton("Get Record", handler));
SpreadsheetApp.getActiveSpreadsheet().show(app);
}
function getResults(eventInfo) {
var app = UiApp.createApplication();
var password = eventInfo.parameter.text;
var panel = app.getElementById("VerticalPanel1");
var textArea = app.createRichTextArea();
panel.add(textArea);
var pointsSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var passwordCheckRange = pointsSheet.getRange("B70:C94").getValues();
...
The problem probably is that when the script is run as a webapp theres no "activeSpreadSheet"
so
SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
fails. An alternate aproach will be to pass the SpreadSheet id in hidden field to the call back.
In your doGet function:
var hidden = app.createHidden('ssId', 'YOUR_SS_ID_HERE');
panel.add(hidden);
var handler = app.createServerHandler("getResults").addCallbackElement(text);
handler.addCallbackElement(hidden)`
In your callback function
var ssID = eventInfo.parameter.ssId;
var pointsSheet = SpreadsheetApp.openById(ssID).getSheetByName('SHEET_NAME');

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.
}