Display a pop up UI based on users' answer - google-apps-script

I currently have a UI with drop down questions. When a user select a certain answer in the drop down list, I want to show another UI that will allow the user to answer more questions. Then, I would like to close this window and return the user to the first UI and continue answering questions.
I have tried popuppanel, set one Ui's invisibility to false but nothing seems to work.
NOTE: Since the data in my first UI are dynamic, I can't use the GUI builder so please only provide solutions using code.
These are the code I have so far:
// when user select this drop down option, show another UI
case 'Move to a special meeting':
displayActionItemsUI();
cellStatus.offset(numOfRowsOffset,0).setValue(N);
cellMeetingType.offset(numOfRowsOffset,0).setValue('Special Meeting');
break;
function displayActionItemsUI() {
var app = UiApp.getActiveApplication();
var panelActionItems = app.createVerticalPanel();
var gridActionItems = app.createGrid(3, 2).setId('gridActionItems')
.setCellPadding(15);
var lblTaskStatement = app.createLabel('Task Statement:');
var lblOwner = app.createLabel('Owner:');
var lblDeadline = app.createLabel('Deadline:');
var tboxTask = app.createTextBox().setId('tboxTask').setName('tboxTask');
var tboxOwner = app.createTextBox().setId('tboxOwner').setName('tboxOwner');
var dboxDeadline = app.createDateBox()
.setFormat(UiApp.DateTimeFormat.DATE_SHORT)
.setId('dboxDeadline').setName('dboxDeadline');
gridActionItems.setWidget(0, 0, lblTaskStatement);
gridActionItems.setWidget(0, 1, tboxTask);
gridActionItems.setWidget(1, 0, lblOwner);
gridActionItems.setWidget(1, 1, tboxOwner);
gridActionItems.setWidget(2, 0, lblDeadline);
gridActionItems.setWidget(2, 1, dboxDeadline);
var btnAdd = app.createButton('Add');
var lblTest = app.createLabel().setId('lblTest').setVisible(false);
panelActionItems.add(gridActionItems)
.add(btnAdd).add(lblTest);
app.add(panelActionItems);
addHandler = app.createServerHandler('_responseToAdd')
.addCallbackElement(panelActionItems);
btnAdd.addClickHandler(addHandler);
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.show(app);
}
// add response to a separate tab and close the UI
function _responseToAdd(e) {
// store user's inputs;
var actionItems = [];
var actionObject = new Object();
var taskStatement = e.parameter.tboxTask;
var owner = e.parameter.tboxOwner;
var deadline = e.parameter.dboxDeadline;
actionObject['task'] = taskStatement;
actionObject['owner'] = owner;
actionObject['deadline'] = deadline;
actionItems.push(actionObject);
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Action Items");
var headers = ['task', 'owner', 'deadline'];
var valuesR = ObjApp.objectToArray(headers, actionItems); //returns [[]]
sheet.getRange(sheet.getLastRow()+1, 1, 1, valuesR[0].length).setValues([valuesR[0]]);
var app = UiApp.getActiveApplication();
var panelActionItems = app.getElementById('panelActionItems');
panelActionItems.clear();
return app;
}

I think you could do it using multiple panels like in this post answer, you could build the panels and change their content depending of the answers...

Related

GUI form does not show up

I'm stuck... My code doesn't want to show me my GUI form.
If I'm trying to add this line: sh=SpreadsheetApp.getActive() before sh.show(app) - script works fine in the script editor. But! If I'm trying to deploy as a web app - script doesn't work.
function doGet() {
var app = UiApp.createApplication().setTitle('test online').setHeight(400).setWidth(600);
var dFormat = UiApp.DateTimeFormat.DATE_LONG
var sh = SpreadsheetApp.openById(spreadsheetID);
var settings = sh.getSheetByName('Name');
var lastrowTime = sh.getSheetByName('Name').getLastRow();
var settings = settings.getRange("A2:A" + lastrowTime).getValues();
var main2 = app.createGrid(1, 4);
var status = app.createLabel().setId('status').setWidth('200');
var card = app.createTextBox().setName('card').setId('card').setWidth('50');
var main1 = app.createGrid(6, 3);
var placeA = app.createTextBox().setId('placeA').setName('placeA').setWidth('400');
var placeB = app.createTextBox().setId('placeB').setName('placeB').setWidth('400');
var phone = app.createTextBox().setId(('phone')).setName('phone').setWidth('200');
var timeTo = app.createListBox(false).setWidth(200).setName('timeTo').addItem("...").setVisibleItemCount(1);
for (var i = 0; i < settings.length; i++) {
timeTo.addItem(settings[i]);
}
var main = app.createGrid(4, 5);
var date = app.createDateBox().setName('date').setFormat(dFormat);
var hour = app.createListBox().setName('hour').setWidth('100');
var min = app.createListBox().setName('min').setWidth('100');
for (h=0;h<24;++h){
if(h<10){var hourstr='0'+h}else{var hourstr=h.toString()}
hour.addItem(hourstr)
}
for (m=0;m<60;++m){
if(m<10){var minstr='0'+m}else{var minstr=m.toString()}
min.addItem(minstr)
}
var refresh = app.createButton('Refresh')
var button = app.createButton('Submit')
var main3 = app.createGrid(1,3);
var price = app.createLabel().setId('price').setWidth('400');
var finalStatus = app.createLabel().setId('finalPrice').setWidth('400');
main2.setWidget(0,0, app.createLabel('Client card: ')).setWidget(0,1, card).setWidget(0,3, status);
main1.setWidget(1,0, app.createLabel('From')).setWidget(1,1,placeA);
main1.setWidget(2,0, app.createLabel('To')).setWidget(2,1,placeB);
main1.setWidget(4,0, app.createLabel('Mobile')).setWidget(4,1,phone);
main1.setWidget(5,0, app.createLabel('Make a call?')).setWidget(5,1,timeTo);
main.setWidget(1,0,app.createLabel('Data')).setWidget(1,1,app.createLabel('hour')).setWidget(1,2,app.createLabel('min'))
main.setWidget(2,0,date).setWidget(2,1,hour).setWidget(2,2,min)
main.setWidget(2,3,refresh).setWidget(2,4, button)
main3.setWidget(0,0, price);
main3.setWidget(0,1, finalStatus);
var serverHandler = app.createServerHandler('show').addCallbackElement(main).addCallbackElement(main1).addCallbackElement(main2).addCallbackElement(main3);
button.addClickHandler(serverHandler)
var handler1 = app.createServerHandler('refresh').addCallbackElement(main).addCallbackElement(main1).addCallbackElement(main2).addCallbackElement(main3);
refresh.addClickHandler(handler1)
var handler2 = app.createServerHandler('checkDate').addCallbackElement(main).addCallbackElement(main1).addCallbackElement(main2).addCallbackElement(main3);
date.addValueChangeHandler(handler2)
app.add(main2)
app.add(main1)
app.add(main)
app.add(main3)
sh.show(app)
}
The methods that you are using to show your UI are specifically for Spreadsheet containers. You've probably read this, to get where you are, but re-read Creating User Interface Elements in UI Service, especially the examples of doGet().
function doGet() { // A script with a user interface that is published as a web app
// must contain a doGet(e) function.
...
return myapp;
}
At the end of the function, you simply need to return your UI App instance. No need to call show, or reference the spreadsheet at all.

Dashboard into StackPanel

I am getting a 'Object Type doesn't match Column Type' error and not sure why... not sure if its something wrong in my code (more than likely) or if it just won't accept the dashboard. I am thinking that my error has to do with the Data Source and how I'm pulling the data from the spreadsheet.
function doGet() {
var app = UiApp.createApplication().setTitle('DHS: Kurzweil Calendar');
//Create stack panel
var stackPanel = app.createStackPanel().setSize('100%', '100%');
var info = about(app);
var p1 = app.createVerticalPanel().setId('vrtPanel1').add(info);
var cal = calendar(app);
var p2 = app.createVerticalPanel().setId('vrtPanel2').add(cal);
var form = formBuild(app);
var p3 = app.createVerticalPanel().setId('vrtPanel3').add(form);
//add widgets to each stack panel, and name the stack panel
stackPanel.add(p1, 'About the Lab');
stackPanel.add(p2, 'Lab Calendar');
stackPanel.add(p3, 'Lab Scheduling');
//Add the panel to the application
app.add(stackPanel);
return app;
}
function about(app){
return app.createHTML('<br />' +
'<p>The Kurzweil Lab at Davie High School supports <i>20 independent student workstations</i> and is designed for the specific use of Kurzweil software. The lab\'s main objective is to support students who have a Read-Aloud accommodation on their Individual Education Plan (IEP). If a student does not have a Read-Aloud accommodation, but has another accommodation like: Separate Setting, Extended Time, or English as a Second Language (ESL) then they are welcome in the lab as long as the lab is not full. If the lab reaches capacity and Read-Aloud students need to use Kurzweil, the student(s) without a Read-Aloud accommodation or who are refusing their Read-Aloud accommodation will be asked to go back to their classroom so that the teacher can make other arrangements for that student.</p>' +
'<p>During non-testing situations the Kurzweil Lab can be scheduled by EC teachers to help with study skills, individual projects, or other work that requires the use of a computer lab.</p>', true);
}
function calendar(app){
// Create Data Source
var ss = SpreadsheetApp.openById('0Aur3owCpuUY-dGJIOGZ1LXhqT2FNMGVXSGNJazFnUmc');
var datasource = ss.getSheetByName('Schedule').getRange(1,1,ss.getLastRow(),ss.getLastColumn());
// Create Charts and Controls
var dateFilter = Charts.newCategoryFilter()
.setFilterColumnLabel("Date").build();
var teacherFilter = Charts.newCategoryFilter()
.setFilterColumnLabel("Teacher").build();
var subjectFilter = Charts.newCategoryFilter()
.setFilterColumnLabel("Subject").build();
var periodFilter = Charts.newCategoryFilter()
.setFilterColumnLabel("Period").build();
var typeFilter = Charts.newCategoryFilter()
.setFilterColumnLabel("Type").build();
var tableChart = Charts.newTableChart().build();
//Create and bind Dashboard
var dashboard = Charts.newDashboardPanel()
.setDataTable(datasource)
.bind([dateFilter, teacherFilter, subjectFilter, periodFilter, typeFilter], [tableChart])
.build();
//Create Application
dashboard.add(app.createVerticalPanel()
.add(app.createHorizontalPanel()
.add(dateFilter).add(teacherFilter).add(subjectFilter).add(periodFilter).add(typeFilter)
.setSpacing(70))
.add(app.createHorizontalPanel()
.add(tableChart)
.setSpacing(10)));
//Add the panel to the application
app.add(dashboard);
return app;
}
You simply forgot that you changed the way every function that build the UI returns data... If you remember your first post about stackPanels we changed the call to
var cal = calendar(app);
and then
var p2 = app.createVerticalPanel().setId('vrtPanel2').add(cal);
So we clearly expect to get a Ui object (a widget) in return.
You can simply change the end of the function calendar(app){ like below :
...
dashboard.add(app.createVerticalPanel()
.add(app.createHorizontalPanel()
.add(dateFilter).add(teacherFilter).add(subjectFilter).add(periodFilter).add(typeFilter)
.setSpacing(70))
.add(app.createHorizontalPanel()
.add(tableChart)
.setSpacing(10)));
//Add the panel to the application
return dashboard;// return the dashboard itself, not the app.
}
EDIT : this was definitely to simple to be true... my answer was correct but obviously didn't include the issues with the dashboard building.
After a few researches (I've never used Charts service before) I came to this code that produces no errors but I'm definitely not sure it returns what you wanted...
Nevertheless it should help you to find your way. (don't blame me if it doesn't look right ;-)
function calendar(app){
// Create Data Source
var ss = SpreadsheetApp.openById('0Aur3owCpuUY-dGJIOGZ1LXhqT2FNMGVXSGNJazFnUmc');
var sh = ss.getSheetByName('Schedule');
var datasource = sh.getRange(1,2,sh.getLastRow(),sh.getLastColumn()).getValues();
Logger.log(datasource)
var dataTable = Charts.newDataTable();
for( var j in datasource[0] ){
dataTable.addColumn(Charts.ColumnType.STRING, datasource[0][j]);
}
for( var i = 1; i < datasource.length; ++i ){
dataTable.addRow(datasource[i].map(String));
}
var dashboard = Charts.newDashboardPanel().setDataTable(dataTable); // Create Charts and Controls
var dateFilter = Charts.newCategoryFilter()
.setFilterColumnLabel("Date").setDataTable(dataTable).build();
var teacherFilter = Charts.newCategoryFilter()
.setFilterColumnLabel("Teacher").setDataTable(dataTable).build();
var subjectFilter = Charts.newCategoryFilter()
.setFilterColumnLabel("Subject").setDataTable(dataTable).build();
var periodFilter = Charts.newCategoryFilter()
.setFilterColumnLabel("Period").setDataTable(dataTable).build();
var typeFilter = Charts.newCategoryFilter()
.setFilterColumnLabel("Type").setDataTable(dataTable).build();
var tableChart = Charts.newTableChart().setDimensions(1000, 600).setDataTable(dataTable).build();
//Create and bind Dashboard
var dashboard = Charts.newDashboardPanel()
.setDataTable(dataTable)
.bind([dateFilter, teacherFilter, subjectFilter, periodFilter, typeFilter], [tableChart])
.build();
//Create Application
var dashBoardPanel = app.createVerticalPanel()
dashBoardPanel.add(app.createHorizontalPanel()
.add(dateFilter).add(teacherFilter).add(subjectFilter).add(periodFilter).add(typeFilter)
.setSpacing(30));
dashBoardPanel.add(tableChart);
//Add the panel to the application
return dashBoardPanel;
}
EDIT 2 : to get the first column as a date you have to slightly modify the for loops that populate the dataTables so that you can convert to string only from the second column.
I did it like this :
function calendar(app){
// Create Data Source
var ss = SpreadsheetApp.openById('0Aur3owCpuUY-dGJIOGZ1LXhqT2FNMGVXSGNJazFnUmc');
var sh = ss.getSheetByName('Schedule');
var datasource = sh.getRange(1,1,sh.getLastRow(),sh.getLastColumn()).getValues();
Logger.log(datasource)
var dataTable = Charts.newDataTable();
dataTable.addColumn(Charts.ColumnType.DATE, datasource[0][1]);
for( var j=2 ;j< datasource[0].length ;++j ){
dataTable.addColumn(Charts.ColumnType.STRING, datasource[0][j]);
}
for( var i = 1; i < datasource.length; ++i ){
var datarow = [];
datarow.push(datasource[i][1]);
for( var j=2 ;j< datasource[0].length ;++j ){
datarow.push(datasource[i][j].toString());
}
dataTable.addRow(datarow);
}
var dashboard = Charts.newDashboardPanel().setDataTable(dataTable); // Create Charts and Controls
...

Google Apps Scrollpanel not updating with information

My script is iterating through some spreadsheet information. I read the documentation and the scrollpanel is only allowed one child. I therefore wrapped the horizontal panel information inside a scrollpanel but for some reason the scrollpanel never shows up with contents just the colored background. Any ideas why this may be?
var myscrollpanel = app.createScrollPanel().setPixelSize(100, 100);
myscrollpanel.setWidth("100%");
myscrollpanel.setStyleAttribute("background", "silver");
var vpanel = app.createVerticalPanel();
for (i=1; i <= mylastrow;++i)
{
var cellsname= mydatarange.getCell(i,1).getValue().toLowerCase();
// Browser.msgBox(cellsname );
// Browser.msgBox(searchstr.toString());
if (cellsname.toString() == searchstr.toString())
{
var panelrow = app.createHorizontalPanel();
var ddate = app.createTextBox();
var sbehavior = app.createTextBox();
var sconsequence = app.createTextBox();
var scomment = app.createLabel();
var steacher = app.createTextBox();
ddate.setText(mydatarange.getCell(i,5).getValue());
sbehavior.setText(mydatarange.getCell(i,8).getValue());
sconsequence.setText(mydatarange.getCell(i,6).getValue());
scomment.setText(mydatarange.getCell(i,10).getValue());
steacher.setText(mydatarange.getCell(i,7).getValue());
panelrow.add(ddate);
panelrow.add(sbehavior);
panelrow.add(sconsequence);
panelrow.add(steacher);
panelrow.add(scomment);
vpanel.add(panelrow);
app.add(panelrow);
cnt = ++cnt;
}
}
// Browser.msgBox(cnt);
myscrollpanel.add(vpanel);
app.add(myscrollpanel);
// return myscrollpanel;
return app ;// update UI
there are a few "anomalies" in your code that could cause some issues, I suggest a couple of changes (see code below).
Another point is that it is not a good idea to read a spreadsheet in a loop, it is mush more efficient to read the whole range in one time and then use the array values to iterate.
Here is a code proposal, I didn't test it (and it will probably need some debugging) but put a few comments to explain the changes.
var myscrollpanel = app.createScrollPanel()//.setPixelSize(100, 100);// 100 pixel is quite small to put all the items you add !!
myscrollpanel.setWidth("100%");//
myscrollpanel.setStyleAttribute("background", "silver");// this will not affect the widgets you add to the panel...
var vpanel = app.createVerticalPanel();
var data = mydatarange.getValues();// get all data in an array
for (i=0; i <data.length;++i) // and work directly with array values (indexed to 0 instead of cells indexed to 1)
{
var cellsname= data[i][0].toString().toLowerCase();
if (cellsname == searchstr.toString()){
var panelrow = app.createHorizontalPanel();
var ddate = app.createTextBox();
var sbehavior = app.createTextBox();
var sconsequence = app.createTextBox();
var scomment = app.createLabel();
var steacher = app.createTextBox();
ddate.setText(data[i][4].getValue());
sbehavior.setText(data[i][7].getValue());
sconsequence.setText(data[i][5].getValue());
scomment.setText(data[i][9].getValue());
steacher.setText(data[i][6].getValue());
panelrow.add(ddate);
panelrow.add(sbehavior);
panelrow.add(sconsequence);
panelrow.add(steacher);
panelrow.add(scomment);
vpanel.add(panelrow);// add only to the panel, not to the app or the row will be outside the panel
cnt = ++cnt;
}
}
myscrollpanel.add(vpanel);
app.add(myscrollpanel);
return app ;// update UI
}

Is there a way to turn off Auto Fill for users when filling out a form?

I think this is a quick one for you, Folks:
I am collecting data in a UiApp built form, and using validation before enabling them to continue. My problem is that often auto-fill will have different format than what is required in my form (such as the state written out instead of a postal abbreviation). I think this may lead to confusion, so I would love to force the users to fill out each box by hand.
Is there a way to turn off the auto-fill function of browsers?
If I were to build in html, would it give me more control of this?
Thanks for the help~
Martin
NOTE: I am using the "ChangeHandler" as it will at least update the validator when autofill is used.
Here's an example code which is of the style I am using. It includes multiple field validation and a review panel. Relevant to my question, but also may be useful for those building forms.
function doGet(e){
var app = UiApp.createApplication().setTitle("Review and Validation");
var appPanel = app.createVerticalPanel();
var form = app.createFormPanel();
var panel1 = app.createGrid(4,5).setId('panel1');
var firstNameLabel = app.createLabel("First Name:");
var firstName = app.createTextBox().setName('firstName').setId('firstName');
var lastNameLabel = app.createLabel("Last Name:");
var lastName = app.createTextBox().setName('lastName').setId('lastName');
var emailLabel = app.createLabel('Your Email');
var email = app.createTextBox().setName('email').setId('email');
var button1 = app.createButton('Go to Review').setEnabled(false);
var info1 = app.createLabel("Please Enter First Name")
.setVisible(false)
.setStyleAttribute('color', 'red');
var info2 = app.createLabel("Please Enter Last Name")
.setVisible(false)
.setStyleAttribute('color', 'red');
var info3 = app.createLabel("Please Enter Email")
.setVisible(false)
.setStyleAttribute('color', 'red');
var syncChangeHandler = app.createServerHandler('syncText').addCallbackElement(form)
.validateLength(firstName, 2, 30).validateLength(lastName, 2, 30).validateEmail(email);
var onValidInput =
app.createClientHandler().validateLength(firstName,2,30).validateLength(lastName,2,30).validateEmail(email).forTargets(
button1).setEnabled(true);
var onInvalidInput1 =
app.createClientHandler().validateNotLength(firstName, 2, 30).forTargets(button1).setEnabled(false).forTargets(info1).setVisible(true);
var onValidInput1 =
app.createClientHandler().validateLength(firstName, 2, 30).forTargets(info1).setVisible(false);
var onInvalidInput2 =
app.createClientHandler().validateNotLength(lastName, 2, 30).forTargets(button1).setEnabled(false).forTargets(info2).setVisible(true);
var onValidInput2 =
app.createClientHandler().validateLength(lastName, 2, 30).forTargets(info2).setVisible(false);
var onInvalidInput3 =
app.createClientHandler().validateNotEmail(email).forTargets(button1).setEnabled(false).forTargets(info3).setVisible(true);
var onValidInput3 =
app.createClientHandler().validateEmail(email).forTargets(info3).setVisible(false);
firstName.addChangeHandler(onInvalidInput1);
firstName.addChangeHandler(onValidInput1);
lastName.addChangeHandler(onInvalidInput2);
lastName.addChangeHandler(onValidInput2);
email.addChangeHandler(onInvalidInput3);
email.addChangeHandler(onValidInput3);
firstName.addChangeHandler(onValidInput);
lastName.addChangeHandler(onValidInput);
email.addChangeHandler(onValidInput);
panel1.setWidget(0,0, firstNameLabel);
panel1.setWidget(0,1, firstName);
panel1.setWidget(0,2, lastNameLabel);
panel1.setWidget(0,3, lastName);
panel1.setWidget(1,1, info1);
panel1.setWidget(1,3, info2);
panel1.setWidget(2,0, emailLabel);
panel1.setWidget(2,1, email);
panel1.setWidget(2,3, button1);
panel1.setWidget(3,1, info3);
app.add(form);
appPanel.add(panel1);
form.add(appPanel);
var panel2 = app.createGrid(4,5).setId('panel2').setVisible(false);
var reviewFirstNameLabel = app.createLabel("First Name:");
var reviewFirstName = app.createLabel().setId('reviewFirstName');
var reviewLastNameLabel = app.createLabel("Last Name:");
var reviewLastName = app.createLabel().setId('reviewLastName');
var reviewEmailLabel = app.createLabel('Your Email:');
var reviewEmail = app.createLabel().setId('reviewEmail');
var submitButton = app.createSubmitButton('Submit');
var button2 = app.createButton('Edit Response');
panel2.setWidget(0,0, reviewFirstNameLabel);
panel2.setWidget(0,1, reviewFirstName);
panel2.setWidget(0,2, reviewLastNameLabel);
panel2.setWidget(0,3, reviewLastName);
panel2.setWidget(1,0, reviewEmailLabel);
panel2.setWidget(1,1, reviewEmail);
panel2.setWidget(2,0, button2);
panel2.setWidget(3,0, 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 syncText(e){
var app = UiApp.getActiveApplication();
app.getElementById('reviewFirstName').setText(e.parameter.firstName);
app.getElementById('reviewLastName').setText(e.parameter.lastName);
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('0Aiapuj1KtAujdHYzZzNzMEsxMUtranZhaXhiSFFnanc').getSheets()[0];
var range = ss.getRange(ss.getLastRow()+1, 1, 1,4);
var values = [[new Date(),e.parameter.firstName, e.parameter.lastName, e.parameter.email]];
range.setValues(values);
var app = UiApp.getActiveApplication();
var label = app.createLabel('Thank You!');
app.add(label);
return app;
}
GAS is globally browser independent since the app is running on Google's Server and doesn't interact directly with your browser... I don't think it is possible to tell the browser to do anything like that and I haven't seen any trick that would make that possible... If I'm wrong then I'd be very curious about it ;-)
Edit : I played with your code and I was wondering if it might not be a solution to use a key press handler instead of click handler so users would be forced to use keyboard to fill the form instead of mouse click. I've seen scripts that check if an 'enter' was pressed to validate an answer. (just an idea)
EDIT 2 : Well, Browsers are too smart, I tested it but autocomplete simulates keypress quite efficiently... too bad :-/

Detecting a null value using a ClientHandler in a Google Apps Scripts GUI

I'm coding a GUI using Google Apps Scripts. I have a text box, for example txtLastName and I would like to add a Client Handler to detect a null value. Essentially, I want to make this a required field.
I guess there are a few possibilities, one of them is to use a length validator
var clientHandler = app.createClientHandler().validateLength(widget, min, max)
and to use this to setVisible a warning message and to disable the 'submit button' eventually...
the documentation on clientHandlers is quite explicit
Here is an example in a simple form that checks question 1 and displays a warning message :
function BuildForm() {
var text= new Array();
text =['question 1','question 2','question 3','question 4','question 5','question 6'];
var textBox = new Array();
var app=UiApp.createApplication().setTitle('Form');
var panel = app.createVerticalPanel().setId('panel');
var btn = app.createButton('process');
var warning = app.createLabel('You forgot to fill in question 1').setVisible(false)
for (nn=0;nn<text.length;++nn){
var label = app.createLabel(text[nn]);
textBox[nn] = app.createTextBox().setName(text[nn].replace(' ',''));
panel.add(label).add(textBox[nn])
}
var cliH1 = app.createClientHandler().validateLength(textBox[0], 0, 1)
.forTargets(btn).setEnabled(false)
.forTargets(warning).setVisible(true)
var cliH2 = app.createClientHandler()
.forTargets(btn).setEnabled(true)
.forTargets(warning).setVisible(false)
var servH = app.createServerHandler('process').addCallbackElement(panel).validateLength(textBox[0], 1, 40)
btn.addClickHandler(cliH1)
textBox[0].addClickHandler(cliH2)
btn.addClickHandler(servH)
panel.add(btn).add(warning)
app.add(panel)
var doc = SpreadsheetApp.getActive();
doc.show(app)
}
function process(e){
var app = UiApp.getActiveApplication()
Browser.msgBox(e.parameter.question1+' '+e.parameter.question2+' '+e.parameter.question3+' '+e.parameter.question4+' '+e.parameter.question5+' '+e.parameter.question6)
app.close()
return app
}
EDIT : here is another version using another validation (validateMatches) and checking all answers
function BuildForm2() {
var text= new Array();
text =['question 1','question 2','question 3','question 4','question 5','question 6'];
var textBox = new Array();
var app=UiApp.createApplication().setTitle('Form');
var panel = app.createVerticalPanel().setId('panel');
var btn = app.createButton('process').setWidth('240');
var warning = app.createLabel('You forgot to fill at least one question').setVisible(false)
for (nn=0;nn<text.length;++nn){
var label = app.createLabel(text[nn]);
textBox[nn] = app.createTextBox().setName(text[nn].replace(/ /g,''));
panel.add(label).add(textBox[nn])
}
var servH = app.createServerHandler('process').addCallbackElement(panel).validateLength(textBox[0], 1, 40).validateLength(textBox[1], 1, 40).validateLength(textBox[2], 1, 40)
.validateLength(textBox[3], 1, 40).validateLength(textBox[4], 1, 40).validateLength(textBox[5], 1, 40);
var cliH = app.createClientHandler().validateMatches(textBox[0],'').validateMatches(textBox[1],'').validateMatches(textBox[2],'').validateMatches(textBox[3],'')
.validateMatches(textBox[4],'').validateMatches(textBox[5],'')
.forTargets(warning).setVisible(true)
btn.addClickHandler(servH).addClickHandler(cliH)
panel.add(btn).add(warning)
app.add(panel)
var doc = SpreadsheetApp.getActive();
doc.show(app)
}