Apps Script GUI and createClientHandler - google-apps-script

I am trying to use a client handler to validate an entry to make sure that the entry is indeed a number. So if an entry contains a letter, for example, then I want to disable a button so that a user cannot proceed. I have built a GUI using the GUI builder, but the client handler, specifically validateNotNumber, does not work if called from the GUI.
So far for a text box I am trying to get the validator to work in, I have in the GUI builder with the ID (Base) = Name (Input Fields), for the Events section I have the "on Key Press" filled in with the name of the function that has the client handler and the name of the form the text box resides on (in my case, AbsolutePanel1).
The function called is:
function isitnotnumbers(e) {
var app = UiApp.getActiveApplication();
app.createClientHandler().validateNotNumber(app.getElementById('ThisOdometer'))
.forTargets(app.getElementById('ButtonCalcMPG')).setEnabled(false);
return app;
};
The function is indeed called I have tested it by having a message displayed when a key is press in the text box. But the button specified is not disabled as it should when a non-number key is pressed.
The examples I found listed the validators in hand coded UI widgets, so I am not sure where I am going wrong when using the GUI builder.
So, where did I go wrong and how can I fix this?
Is there a work around if the GUI builder does have limitations with client handlers (such as using the HTML service)?
My other attempt(s):
I have tried to add a click handler to the text box, which is a modification to the code above:
var app = UiApp.getActiveApplication();
var handlernumbers = app.createClientHandler()
.forTargets(app.getElementById('LabelUserMessage'))
.setText('THe message');
var odobox = app.getElementById('ThisOdometer');
odobox.addClickHandler(handlernumbers);
return app;

Try this:
function isitnotnumbers(e) {
var app = UiApp.getActiveApplication();
app.getElementById('ThisOdometer').addKeyUpHandler(app.createClientHandler().validateNotNumber(app.getElementById('ThisOdometer'))
.forTargets(app.getElementById('ButtonCalcMPG')).setEnabled(false));
return app;
};
Edit:
You don't need this code in a separate function, just add the following line to your doGet() or in the main function (so that the handler is created only once when the app launches):
app.getElementById('ThisOdometer').addKeyUpHandler(app.createClientHandler().validateNotNumber(app.getElementById('ThisOdometer'))
.forTargets(app.getElementById('ButtonCalcMPG')).setEnabled(false));

To answer my own question, I will say that it does not matter as google is deprecating gui builder, and will cease to function after September.
I should, or perhaps I should have started to, learn uiservice or htmlservice.

Related

How to get element ID in UiApp

I am trying to create an app script for a Google Spreadsheet that I have. I created a script for another sheet a couple of years ago and I can't remember how to to get the component ID.
Here's the code:
var pointsSheet = SpreadsheetApp.openById('1o8_f063j1jYZjFEnI_P7uAztpnEAvQ6mc3Z1_Owa69Y');
function doGet() {
var app = UiApp.createApplication();
app.add(app.loadComponent("Marks")); //IT IS NOT CALLED MARKS!
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);
return app;
}
...
The commented part where it says "IT IS NOT CALLED MARKS" is the part I'm talking about. In my other script this works, but in the new script it doesn't work. How do I find the component name (if that's what it's called)?
You are trying to run a script that uses the GUI Builder, a couple of years ago it was possible but now it is not anymore (since october 2013)! See here.
I saw that because you are using app.loadComponent("Marks"), which was the method to call the Ui components created in the GUI Builder.
The old apps built with it still work but you can't create/modify it.
EDIT following your comment :
You will have to build your UI from scratch using either UiApp - which uses the same elements as the GUI builder and the same syntax - or HTML Service.
The latter is much more powerfull but uses a completely different approach as it uses client JavaScript in combination with server code. Take a look at the docs and tutos and make your choice ;-)

Basic UiApp failing with error "ReferenceError: "UIApp" is not defined."

I am creating some google app scripts for my company to use to generate random tests for employee training. I already have the basic scripts written to grab a list of questions from a google sheet, randomize them, grab the first 10 questions, etc. That all works fine. I decided it might be better to re-do the whole thing using a UiApp instead of just separate scripts. That is where the problem comes in. I did a simple bare bones UiApp to test with, published it and tried to hit the URL and that's where I encounter this error. I searched for this error and all I could find was some discussion about this being part of google apps premiere(which should have been folded into regular google apps around 2010). I've been staring at this so long I've frustrated myself. It should be something very simple and yet it's refusing to work. I'm assuming I am doing something wrong at a basic level but I've reached the point where my brain refuses to see it.
Here is the basic script I started with:
function doGet(e) {
var app = UiApp.createApplication();
var mainPanel = app.createVerticalPanel().setId('mainPanel');
mainPanel.add(app.createLabel('test'));
return app;
}
I save it, publish it and go to the URL and that's when I get the above error message. I know it's something simple but I've reached the point of frustration and simply can't see it.
Update: to reflect comments
Another possibility for WebApps not updating is not publishing a new version and only checking the exec URL. For instant changes to the code, always check the dev URL. The exec will only change after saving a version in Manage Versions and re-publishing the app.
First Answer:
I think your question title says it all.
UIApp is not defined, but Class is UiApp. JS is case sensitive. I copied and pasted the code exactly as it is in your question and received no errors. I did have to add one line to make the label show up.
function doGet(e) {
var app = UiApp.createApplication();
var mainPanel = app.createVerticalPanel().setId('mainPanel');
mainPanel.add(app.createLabel('test'));
app.add(mainPanel); // <-- I added this line to see the label
return app;
}

Google Apps Script Close()

Is it possible to close a UI window that has opened in Apps Script?
I think the answer is no per: http://code.google.com/p/google-apps-script-issues/issues/detail?id=474&can=1&q=.close%28%29&colspec=Stars%20Opened%20ID%20Type%20Status%20Summary%20Component%20Owner
but I wanted to see if there were other opinions.
I have a "Waiting window" that pops up, that I want to close when the activity is finished.
var app = UiApp.getActiveApplication();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = getSheetWithSubmissions(ss);
// create UI app, this works fine
app = createWaitPleaseUI(sheet);
ss.show(app);
//simulated activity
Utilities.sleep(5000);
//this doesn't work despite being in the documentation
app.close();
Think this is not possible but wish Google would dump it from their documentation if it can't be done.
As a workaround, I can bring up a second GUI saying "work complete, click OK" and then it works fine.
You have to return the app object for any changes to be updated to it, even closing.
Change your last line to return app.close() instead.
You should read the documentation more thoroughly, it is clearly explained that UI in spreadsheets need to be ended by a return to actually close. Also I would suggest that you might trust the answer coming from a top contributor instead of believing that you are always right against the doc and everybody else ... no offence but a bit of humility is always welcome :-)
here is an piece of code extracted from the documentation to corroborate :
// Close everything return when the close button is clicked
function close() {
var app = UiApp.getActiveApplication();
app.close();
// The following line is REQUIRED for the widget to actually close.
return app;
}

Problems using the Apps Script GUI builder

So I'm currently working on the gui of an item checkout system that runs within a spreadsheet. It does everything it's supposed to and isn't returning anything null, usually I'd be really happy with how it's turning out.
However, I keep getting "error encountered, an unexpected error occured" whenever I press the submit button, after that the rest of the code runs as expected. Every once and a while I'll get no error, but the vast majority of the time it throws the error.
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [{name: "Equipment Checkout", functionName: "testing"}];
ss.addMenu("Equipment Checkout", menuEntries);
}
function testing(){
var app = UiApp.createApplication();
app.add(app.loadComponent("ImprovedCheckout"));
var doc = SpreadsheetApp.getActiveSpreadsheet();
doc.show(app);
}
function submitted(e){
Browser.msgBox(e.parameter.requestor);
}
This is the simplest version of my code.
I'm using the gui builder to create the gui and I'm also using it to make the event handler. I've been banging my head against the wall for the past hour because it seems like the error is happening before the first line of submitted(e) but it doesn't occur until I actually click the submit button. It doesn't happen every time but it does happen the majority of the time.
I imagine I'm handling events from the builder wrong but there is oh so little information on that feature yet.
I've seen this error happen when people set two handlers for the same button. Normally one via the GUI editor and another on the code. One works and the other fails. Which gives this crazy impression that it throws an error and yet works.
But since you said this is the exact code you're using. Are you setting multiple handlers on the GUI builder? I don't know even if that's possible, I never use the GUI builder.
FIGURED IT OUT!
Instead of using a submit button, I changed it to just a regular old button. It looks like the submit button was trying to run something else at the same time.
It looks like submit buttons have some additional rules and requirements but for the time being, I'm just using a normal button.
I have had no issues running the code you have supplied. Two things to mention that are key:
Make sure that you're adding a callback element to the ServerHandler with the HTML name of "requestor" as you are using in code.
When you add the callback element, use the ID in the GUI editor. Name != ID
Both Name and ID need to be set in this example.
I have got this same error message when using getElementbyId('id") and having a wrong value as ID. The script itself don't really stop and everything might seem normal apart from the action this specific call is supposed to do (but this is not always 'obvious')

GUI not passing values to spreadsheet

I've created a GUI (MyGui) with a flow panel (mainPanel), a text box (textValue) and a button (getETA). All in a sites script.
The idea is that a value is entered in the text box, the button is clicked and the value is then placed in the cell A1 of a spreadsheet.
There is no handler configured in the GUI and I've copy pasted the script to a fresh site, no success though.
The problem I'm having is that all I get in the spreadsheet cell is "undefined".
Also if I run a debug on the clickGetETA function I get the following error message: "Cannot read property "parameter" from undefined"
I'm new to this but my best guess is that the details of the GUI are not being passed on to the clickGetETA function. I've searched what I can but I can't appear to find a solution...
If someone could tell me where I'm going wrong I'd appreciate he help.
function doGet() {
var app= UiApp.createApplication();
app.add(app.loadComponent("MyGui"));
var clickHandler = app.createServerHandler('clickGetETA');
clickHandler.addCallbackElement(app.getElementById('mainPanel'));
app.getElementById('getETA').addClickHandler(clickHandler);
return app;
}
function clickGetETA(e) {
var sheet = SpreadsheetApp.openById('abcdefghjklmnopqrstuvwxyz');
var ss = sheet.getActiveSheet();
var target = ss.setActiveCell("A1");
target.setValue(e.parameter.textValue);
}
Change:
var ss = sheet.getActiveSheet();
var target = ss.setActiveCell("A1");
To :
var ss = sheet.getSheetByName("SheetName");
var target = ss.getRange("A1");
Good examples for this kind of thing are here:
https://developers.google.com/apps-script/guide_user_interfaces
It should be run as a service. i.e. you use the get function.
Notes: the "e" parameter does not exist when you debug. Debugging is a little limited.
ActiveSheet and ActiveCell are designed to be used from a spreadsheet not a service.
A service creates a web page rather than a popup box.
Eddy.
The callback element used in the addCallbackElement may be a single widget or the a panel of your GUI. When passing a panel, all widgets bellow in the panel hierarchy will be included in the parameter. Are you sure your textbox is inside the panel you're adding?
Also, the values of the widgets can be accessed in the handler function using the widget name (that you must set on the GUI builder). Notice the difference between name and id, the id you use to get the widget using getElementById and also to determine the widget source of the events, when you use the same handler for multiple widgets. And the name for accessing the value. Are you sure you named your textbox as textValue?
What fixed it for me was going into the UI editor and making sure I had an ID assigned for form fields and a name. I was missing the name so my e.parameter.fieldName was undefined.