I'm confused about the behavior of the following code sample.
Why can't I access statusLabelU in the callback via the app object ?
It is available in the argument
BTW, what is the type of the argument variable e in the callback ?
function doGet() {
var app = UiApp.createApplication();
var button = app.createButton('Enter Symbol');
app.add(button);
var symbolText = app.createTextBox().setName('symbolText').setId('symbolText');
app.add(symbolText);
var labelU = app.createLabel('Unknown symbol U')
.setId('statusLabelU');
var labelK = app.createLabel('Unknown symbol K')
.setId('statusLabelK');
app.add(labelU);
app.add(labelK);
var handler = app.createServerHandler('myClickHandler');
handler.addCallbackElement(symbolText);
button.addClickHandler(handler);
return app;
}
function myClickHandler(e) {
var app = UiApp.getActiveApplication();
var symU = app.getElementById('symbolText');
var symK = e.parameter.symbolText;
var financeU = FinanceApp.getStockInfo(symU);
var financeK = FinanceApp.getStockInfo(symK);
var label = app.getElementById('statusLabelU');
label.setText(financeU.name);
var label = app.getElementById('statusLabelK');
label.setText(financeK.name);
app.close();
return app;
}
If you run
labelU.setName('labelU');
handler.addCallbackElement(labelU);
you will be be able to access the value of the label in the callback like so:
var value = e.parameter.labelU;
The argument 'e' (or 'eventInfo') contains information about how the callback was triggered. There is some general information about user ID, x/y position of cursor, and also the source element that triggered the callback. Apart from that, values from widgets that are explicitly added to the handler will be accessible as parameters. You can always check out the content by doing a
Logger.log(e);
and check out the log from the coding environment (cmd/ctrl + return).
Actually you can access statusLabelU in the callback via the app object. What you cannot do (at least I dont know any way) to access the contents of a TextBox except than passing it as a parameter to your event-handler via addCallbackElement (you can also pass a container to addCallbackElement, then all elements in this container are passed to your event-handler). So what happens in your example:
var symU = app.getElementById('symbolText');
returns a kind of Proxy of your TextBox, which returns, when converted to a string 'Generic'.
FinanceApp.getStockInfo('Generic');
then in turn returns undefined, which is then set as Text of your label statusLabelU.
Yeah it took me a while to understand what was going on. The way I finally understood it is this:
The server processes stuff, then serves up UI to the client. Every time the client does something, like click a button, he submits this stuff to the server, but the server has no recollection of what it did before, so all those variables you made prior to serving the UI to the client, it no longer knows.
Thus if you want the server to remember those values it created from before serving the client, then you need to embed them along with the UI sent to the client so that when he does something, the data gets sent back to the server.
That embedded crap is considered a hidden callback element, something the user doesn't interact with, and is solely there to pass it back to the server during the next processing action. The 'normal' callback elements are data the server doesn't know yet, such as form elements (names, addresses, etc). It will need to know this information once the user hits the submit button to process it, so that's why it's called callback info.