I try to create filter number - google-apps-script

I try to create filter number: the value of textBox filter accept only number.
you can help me please
The filter accepts a int or fload not int var
function callok(e){
var app = UiApp.getActiveApplication();
var montantEE = e.parametre.MontantEE;
if (montantEE==number){app.getElementById('validateLabel').setText('PleaseMontant !');
}else{
app.getElementById('validateLabel').setText('You entered: '+ e.parametre.MontantEE);
return app;

Not exactly sure I understood precisely your requirements but I'd suggest you use a validator coupled with a clientHandler to achieve what you need.
Simply add a integer-validator to a clientHandler that will enable the button you probably use to submit the values. Use an nonInteger validator to ensure that any typing correction is handled as well.
Here is an example code and a test app online
var app = UiApp.createApplication().setTitle('test sidebar');
var panel = app.createVerticalPanel();
var btn = app.createButton('submit').setEnabled(false);
var inputBox = app.createTextBox().setName('num');
var cHandler1 = app.createClientHandler().validateInteger(inputBox).forTargets(btn).setEnabled(true).forEventSource().setStyleAttribute('backgroundColor','lightgreen');
var cHandler2 = app.createClientHandler().validateNotInteger(inputBox).forTargets(btn).setEnabled(false).forEventSource().setStyleAttribute('backgroundColor','red');
inputBox.addKeyUpHandler(cHandler1).addKeyUpHandler(cHandler2);
panel.add(inputBox).add(btn);
return app.add(panel);

Related

how to get value of Hidden object

I need global variable in google script, to hold page ID, like a string. Here, they suggested to use object Hidden for this purpose. I can create this object and set its value.
Code to achieve the same :
function doGet(e) {
var app = UiApp.createApplication();
//Get current indentificator
var mid = 'page-id';
app.add( app.createHidden('mid').setValue(mid).setId('mid'));
return app;
}
But how can I get this value from another function?
For example :
function maketbl(){
var app = UiApp.getActiveApplication();
app.(?!)
}
Thanks!
I see that your requirement is to have functionality similar to that of global variables. I suggest that you use script properties, user properties or the cache service to accomplish this feat. An example is below
ScriptProperties.setProperty('special', 'sauce'); // Use this to set the property
var specialValue = ScriptProperties.getProperty('special'); // use this to access the property
Try the bellow code:
function doGet(e) {
var app = UiApp.createApplication();
var mid = 'page-id';
var hidden = app.createHidden('mid').setValue(mid).setId('mid');
app.add(hidden);
//Create your handler
var handler = app.createServerHandler('maketbl');
handler.addCallbackElement(hidden)
//Create a button to trigger your function
app.add(app.createButton().setText("go forest").addClickHandler(handler));
return app;
}
function maketbl(e){
var app = UiApp.getActiveApplication();
//Retrieve the hidden field
var hidden = app.getElementById("mid");
//Show the value stored at e.parameter.mid where mid is the name of the field
var dialogBox = app.createDialogBox().setText(e.parameter.mid);
dialogBox.setPopupPosition(100, 100);
dialogBox.show();
return app;
}
Live version here.

How to access source widget's value in GAS?

I'm trying to write a generic server handler for textboxes which highlights the text when the textbox gains focus:
function onFocusHighlight(e) {
var app = UiApp.getActiveApplication();
var widget = app.getElementById(e.parameter.source);
var widgetValue = e.parameter.widgetName; // how can I get widgetName from source???
widget.setSelectionRange(0, widgetValue.length);
return app;
}
Can I determine widgetValue from e.parameter.source?
var widget = app.getElementById(e.parameter.source).setName("widgetName")
Then get widgetValue:
var widgetValue = e.parameter.widgetName
Check https://developers.google.com/apps-script/uiapp for usage of setName.
I've found that as long as widgetName and widgetId are the same I can determine widgetValue as follows:
function onFocusHighlight(e) {
var app = UiApp.getActiveApplication();
var widgetId = e.parameter.source;
var widgetName = widgetId; // name MUST match id to retrieve widget value
var widgetValue = e.parameter[widgetName]; // not sure why this syntax works???
var widget = app.getElementById(widgetId);
widget.setSelectionRange(0,widgetValue.length);
return app;
}
My only issue now is understanding how/why the e.parameter[widgetName] syntax actually works. It would also be great to have a solution which doesn't rely on widgetName and widgetId being the same value.
Just a suggestion following your own answer :
You could probably make it work by having a conversion table somewhere that gets the widgets name from their ID.
For example you could define :
ScriptProperties.setProperties({'widgetID1':'Name1','widgetID2':'name2'},true)
and then
widgetvalue = e.parameter[ScriptProperties.getProperty(e.parameter.source)]
I didn't test this code but it seems logical ;-), tell me if it doesn't (I don't have time to test it now)
EDIT : works as expected, here is a test sheet to show the result, test code below.
function Test(){
var app = UiApp.createApplication().setTitle('test');
app.add(app.createLabel('Type anything in upper textBox and then move your mouse over it...'))
var p = app.createVerticalPanel()
var txt1 = app.createTextBox().setId('txt1').setName('Name1').setValue('value in TextBox1')
var txt2 = app.createTextBox().setId('txt2').setName('Name2').setValue('waiting to mouseOver textBox1')
p.add(txt1).add(txt2)
app.add(p)
var handler = app.createServerHandler('mouseOver').addCallbackElement(p);
txt1.addMouseOverHandler(handler);
ScriptProperties.setProperties({'txt1':'Name1','txt2':'Name2'},true);//save the name, only txt1 will be used here
var ss=SpreadsheetApp.getActiveSpreadsheet()
ss.show(app)
}
function mouseOver(e) {
var app = UiApp.getActiveApplication();
var widget = app.getElementById(e.parameter.source);
var widgetValue = e.parameter[ScriptProperties.getProperty(e.parameter.source)]; // ScriptProperties knows the Widget's name
app.getElementById('txt2').setValue(widgetValue) ;// Use the other widget to show result
return app;
}

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 :-/

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

GAS Client Handler Validation on List Boxes

I am coding a simple UI web form in GAS. I have several text boxes and list boxes. I have added client handlers to validate the input on the text boxes on blur and they all work fine. However, when I try to use the client handler on a list box it doesn't work. For example, the first item in the list box is an empty string and I want to check that an item has been picked. Whatever validation option I use, it fires. I've tried validate length. I thought perhaps the script might be picking up the index value of the list so I tried option and range. Also, a no-go. I would guess the script is working with a null value which is short-circuiting any validation. Any tips? When the widget is a List Box this thing fires all the time regardless of the conditions.
var required_field = app.createClientHandler()
.validateNotLength(widget, min, max)
.forTargets(lblInfo)
.setStyleAttribute('color','red')
.setText('Please correct errors in red NOW.')
.forTargets(lbl)
.setStyleAttribute('color','red')
.forTargets(widget)
.setStyleAttribute('background', '#ffe7e7');
widget.addBlurHandler(required_field);
I was interested in this issue so I ran a couple of tests and ended up with a workaround that might be interesting. The code is a bit long but I didn't find any way to make it shorter and still clear ;-)
This version is working, there are a few comments to suggest how to make it 'transparent' and also how to demonstrate that the handlers validation doesn't work on listBoxes.
Tell me what you think ;-)
EDIT : I've put a version online for a quick test.
function showtest() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var app = UiApp.createApplication().setTitle('ListBox Clienthandler test');
var panel = app.createVerticalPanel();
var lb = app.createListBox(false).setId('myId').setName('myLbName').setWidth(350);
var former = app.createTextBox().setName('former value').setId('former').setWidth(350);
var textbox = app.createTextBox().setName('text').setId('valtext').setWidth(350)//.setVisible(false);// set it visible to test how it works, invisible to use it 'transparently'
var label = app.createHTML("<BR><BR>Use this textBox as a button, click on it to update its value,<BR>the Client handler doesn't fire when selected color = white<BR>(if you set the upper textBox invisible then it works as if the<BR>listBox had the handler)<BR><BR>")
// add items to ListBox
lb.setVisibleItemCount(7);
lb.addItem('white');
lb.addItem('pink');
lb.addItem('orange');
lb.addItem('green');
lb.addItem('yellow');
lb.addItem('red');
lb.addItem('cyan');
//
panel.add(textbox);
panel.add(lb);
panel.add(label);
panel.add(former);
var handler = app.createServerClickHandler('click').addCallbackElement(panel);
lb.addClickHandler(handler);
app.add(panel);
doc.show(app);
}
//
function click(e) {
var app = UiApp.getActiveApplication();
var value = e.parameter.myLbName
if(value==''){value='white'}
var textboxvalue = e.parameter.text
if(textboxvalue==''){textboxvalue='none'}
var text=app.getElementById('valtext')
text.setText(value)
var lb=app.getElementById('myId')
var former=app.getElementById('former')
// var handlerval = app.createClientHandler().validateNotMatches(lb, 'white') // this line puts handler on listBox and doesn't work
var handlerval = app.createClientHandler().validateNotMatches(text, 'white') // this line puts handler on TextBox and works as expected
.forEventSource().setText("Click here for Former Value = "+textboxvalue+" / present value = "+value)
.forTargets(lb).setStyleAttribute("background", value)
former.addClickHandler(handlerval);
return app;
}
EDIT 2 :
here is another possibility to simulate (almost exactly) the function you need : (online version)
function showtest() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var app = UiApp.createApplication().setTitle('ListBox Clienthandler test');
var panel = app.createVerticalPanel();
var lb = app.createListBox(false).setId('lb').setName('lb').setWidth(350);
var label = app.createHTML("<BR>You forgot to choose a value in the list").setVisible(false).setId('label');
lb.setVisibleItemCount(7);
lb.addItem('');
lb.addItem('pink');
lb.addItem('orange');
lb.addItem('green');
lb.addItem('yellow');
lb.addItem('red');
lb.addItem('cyan');
var othertextbox = app.createTextBox().setText('other question');
var grid = app.createGrid(4,1)
grid.setWidget(0, 0, lb)
grid.setWidget(1, 0, label)
grid.setWidget(3, 0, othertextbox)
panel.add(grid)
var handler = app.createServerBlurHandler('alert').addCallbackElement(panel);
lb.addBlurHandler(handler);
app.add(panel);
doc.show(app);
}
//
function alert(e) {
var app = UiApp.getActiveApplication();
var lb = app.getElementById('lb')
var label = app.getElementById('label')
var value = e.parameter.lb
if(value==''){
lb.setStyleAttribute("background", 'red');
label.setVisible(true)
}else{
lb.setStyleAttribute("background", 'white');
label.setVisible(false)
}
return app;
Client handlers dont work with ListBox. But don't forget that you always have an option with Server handlers which are applicable in most of the cases when you can 1-2 seconds lag in reaction