Google-apps-script Client Validation
/I recently saw a question on stackoverflow where someone was asking if it was possible to do a two-factor clienthandler to validate entries. Since I've only been playing with apps scripts for a week (see my other posts on adventures with archiving Gmail - which I still have to finish up), I figured I'd give it a try to learn a bit more.
The scenario was he (or she) had two textboxes and wanted to allow a button to be clicked if either BOTH were empty OR BOTH had data. My solution, while cumbersome, actually works.
I created two additional textboxes (which could be hidden) then piled on the validators on the original two texboxes.
- If entryTextbox1.length>0, validatorTextbox1.text=1 else validatorTextbox1=0,
- If entryTextbox2.length>0, validatorTextbox2.text=1 else validatorTextbox2=0
Then some textchangehandlers
- validatorTextbox1.onTextChange: if sum(validatorText1+validatorTextbox2)=1, don't allow click
- validatorTextbox2.onTextChange: if sum(validatorText1+validatorTextbox2)=1, don't allow click
To handle databoxes, the theory is the same, but
- lengthchecks on dateboxes don't work properly they throw an error for some reason. i used a regex testing for the '-' character. you may need to change this if you've formated your date differently. Or you could fully validate the date format.
- you need to fire events for invalid dates to handle empty fields
- and lastly, you need to use the valuechange handler instead as it was correctly pointed out it doesn't have onkeyup
Click Here to see the solution in action.
function doGet() {
var app = UiApp.createApplication();
var buttonDate = app.createButton('Click Me');
app.add(app.createLabel("This demonstrates using clienthandlers to require either neither or both dateBoxes to be populated before the button can be clicked"));
var validationWarning=app.createLabel("Please enter a value in both fields or neither field").setId('warningLabel').setStyleAttribute('color', "red").setVisible(false);
app.add(buttonDate);
app.add(validationWarning);
var panel = app.createVerticalPanel();
// db1.addValueChangeHandler(handler);
var db1=app.createDateBox().setId('db1').setName('db1');
var db2=app.createDateBox().setId('db2').setName('db2');
//Hide these two - but i left them visible so you can see the script in action.
var tbValidatorFordb1=app.createTextBox().setId('tb3').setName('tb3').setEnabled(false);
var tbValidatorFordb2=app.createTextBox().setId('tb4').setName('tb4').setEnabled(false);
var label1 = app.createLabel('The button was clicked.')
.setId('statusLabel')
.setVisible(false);
panel.add(label1);
var grid1=app.createGrid(2, 2);
grid1.setWidget(0, 0, app.createLabel("Field 1"));
grid1.setWidget(0, 1, app.createLabel("Field 2"));
grid1.setWidget(1, 0,db1);
grid1.setWidget(1, 1,db2);
panel.add(grid1);
var grid2=app.createGrid(2, 2);
grid2.setWidget(0, 0, app.createLabel("Validator 1"));
grid2.setWidget(0, 1, app.createLabel("Validator 2"));
grid2.setWidget(1, 0,tbValidatorFordb1);
grid2.setWidget(1, 1,tbValidatorFordb2);
panel.add(grid2);
app.add(panel);
//Set your validators for your first textbox
var clientHandler1=app.createClientHandler().validateMatches(db1,'\-').forTargets(tbValidatorFordb1).setText('1');
var clientHandler2=app.createClientHandler().validateNotMatches(db1, '\-').forTargets(tbValidatorFordb1).setText('0');
//Set your validators for your second textbox
var clientHandler3=app.createClientHandler().validateMatches(db2,'\-').forTargets(tbValidatorFordb2).setText('1');
var clientHandler4=app.createClientHandler().validateNotMatches(db2,'\-').forTargets(tbValidatorFordb2).setText('0');
//tb1.addValueChangeHandler(handler)
db1.addValueChangeHandler(clientHandler1);
db1.addValueChangeHandler(clientHandler2);
db2.addValueChangeHandler(clientHandler3);
db2.addValueChangeHandler(clientHandler4);
db2.addValueChangeHandler(clientHandler1);
db2.addValueChangeHandler(clientHandler2);
db1.addValueChangeHandler(clientHandler3);
db1.addValueChangeHandler(clientHandler4);
//Now create some client handlers to do the actual enable/disable of the button
db1.setFireEventsForInvalid(true);
db2.setFireEventsForInvalid(true);
var finalDisableValidator1=app.createClientHandler().validateSum([tbValidatorFordb1,tbValidatorFordb2], 1).forTargets(buttonDate).setEnabled(false).forTargets(validationWarning).setVisible(true);
var finalEnableValidator1=app.createClientHandler().validateNotSum([tbValidatorFordb1,tbValidatorFordb2], 1).forTargets(buttonDate).setEnabled(true).forTargets(validationWarning).setVisible(false);
db1.addValueChangeHandler(finalDisableValidator1);
db1.addValueChangeHandler(finalEnableValidator1);
db2.addValueChangeHandler(finalDisableValidator1);
db2.addValueChangeHandler(finalEnableValidator1);
//tb4.addChangeHandler(finalEnableValidator)
var handler = app.createServerHandler('myClickHandler').validateNotSum([tbValidatorFordb1,tbValidatorFordb2], 1);
handler.addCallbackElement(label1);
buttonDate.addClickHandler(handler);
//Code for textboxes
var button2 = app.createButton('Click Me');
var panel2 = app.createVerticalPanel();
panel2.add(app.createLabel("This demonstrates using clienthandlers to require either neither or both textBoxes to be populated before the button can be clicked"));
var validationWarning2=app.createLabel("Please enter a value in both fields or neither field").setId('warningLabel').setStyleAttribute('color', "red").setVisible(false);
panel2.add(button2);
panel2.add(validationWarning2);
// db1.addValueChangeHandler(handler);
var tb1=app.createTextBox().setId('tb1').setName('tb1');
var tb2=app.createTextBox().setId('tb2').setName('tb2');
//Hide these two - but i left them visible so you can see the script in action.
var tbValidatorForTb1=app.createTextBox().setId('tb5').setName('tb5').setEnabled(false);
var tbValidatorForTb2=app.createTextBox().setId('tb6').setName('tb6').setEnabled(false);
var label = app.createLabel('The button was clicked.')
.setId('statusLabel')
.setVisible(false);
panel2.add(label);
var grid3=app.createGrid(2, 2);
grid3.setWidget(0, 0, app.createLabel("Field 1"));
grid3.setWidget(0, 1, app.createLabel("Field 2"));
grid3.setWidget(1, 0,tb1);
grid3.setWidget(1, 1,tb2);
panel2.add(grid3);
var grid4=app.createGrid(2, 2);
grid4.setWidget(0, 0, app.createLabel("Validator 1"));
grid4.setWidget(0, 1, app.createLabel("Validator 2"));
grid4.setWidget(1, 0,tbValidatorForTb1);
grid4.setWidget(1, 1,tbValidatorForTb2);
panel2.add(grid4);
app.add(panel2);
//Set your validators for your first textbox
var clientHandler5=app.createClientHandler().validateLength(tb1, 1, 200).forTargets(tbValidatorForTb1).setText('1');
var clientHandler6=app.createClientHandler().validateLength(tb1,0, 0).forTargets(tbValidatorForTb1).setText('0');
//Set your validators for your second textbox
var clientHandler7=app.createClientHandler().validateLength(tb2, 1, 200).forTargets(tbValidatorForTb2).setText('1');
var clientHandler8=app.createClientHandler().validateLength(tb2,0, 0).forTargets(tbValidatorForTb2).setText('0');
//tb1.addValueChangeHandler(handler)
tb1.addKeyUpHandler(clientHandler5);
tb1.addKeyUpHandler(clientHandler6);
tb2.addKeyUpHandler(clientHandler7);
tb2.addKeyUpHandler(clientHandler8);
tb2.addKeyUpHandler(clientHandler5);
tb2.addKeyUpHandler(clientHandler6);
tb1.addKeyUpHandler(clientHandler7);
tb1.addKeyUpHandler(clientHandler8);
//Now create some client handlers to do the actual enable/disable of the button
var finalDisableValidator=app.createClientHandler().validateSum([tbValidatorForTb1,tbValidatorForTb2], 1).forTargets(button2).setEnabled(false).forTargets(validationWarning).setVisible(true);
var finalEnableValidator=app.createClientHandler().validateNotSum([tbValidatorForTb1,tbValidatorForTb2], 1).forTargets(button2).setEnabled(true).forTargets(validationWarning).setVisible(false);
tb1.addKeyUpHandler(finalDisableValidator);
tb1.addKeyUpHandler(finalEnableValidator);
tb2.addKeyUpHandler(finalDisableValidator);
tb2.addKeyUpHandler(finalEnableValidator);
//tb4.addChangeHandler(finalEnableValidator)
var handler = app.createServerHandler('myClickHandler').validateNotSum([tbValidatorForTb1,tbValidatorForTb2], 1);
handler.addCallbackElement(label);
button2.addClickHandler(handler);
return app;
}
function myClickHandler(e) {
var app = UiApp.getActiveApplication();
var label = app.getElementById('statusLabel');
label.setVisible(true);
app.close();
return app;
}