how to get value of Hidden object - google-apps-script

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.

Related

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;
}

How to make the last item added to a flextable return directly underneath the previous item?

Could someone please show me how to make the last item added to the flextable go directly underneath the existing item?
function doGet() {
var app = UiApp.createApplication();
var listBox = app.createListBox();
listBox.addItem("item 1").addItem("item 2").addItem("item 3").setName("myListBox");
var handler = app.createServerHandler("buttonHandler");
// pass the listbox into the handler function as a parameter
handler.addCallbackElement(listBox);
var table = app.createFlexTable().setId("myTable");
var button = app.createButton("+", handler);
app.add(listBox);
app.add(button);
app.add(table);
return app;
}
function buttonHandler(e) {
var app = UiApp.getActiveApplication();
app.getElementById("myTable").insertRow(0).insertCell( 0, 0).setText( 0, 0, e.parameter.myListBox);
return app;
}
The idea is to keep in memory the index of the row you write to. One can use many ways to achieve this but the most straightforward is probably to write this row index in the table or listBox tag, something like this (I didn't test the code but hope I made no error):
EDIT : the tag solution didn't seem to work, so I changed to a hidden widget solution.(tested)
function doGet() {
var app = UiApp.createApplication();
var listBox = app.createListBox();
listBox.addItem("item 1").addItem("item 2").addItem("item 3").setName("myListBox");
var hidden = app.createHidden().setName('hidden').setId('hidden')
var handler = app.createServerHandler("buttonHandler");
// pass the listbox into the handler function as a parameter and the hidden widget as well
handler.addCallbackElement(listBox).addCallbackElement(hidden);
var table = app.createFlexTable().setId("myTable");
var button = app.createButton("+", handler);
app.add(listBox).add(button).add(table).add(hidden);// add all widgets to the app
return app;
}
function buttonHandler(e) {
var app = UiApp.getActiveApplication();
var pos = e.parameter.hidden;// get the position (is a string)
if(pos==null){pos='0'};// initial condition, hidden widget is empty
pos=Number(pos);// convert to number
var table = app.getElementById("myTable")
table.insertRow(pos).insertCell( pos, 0).setText(pos, 0, e.parameter.myListBox);// add the new item at the right place
++pos ;// increment position
app.getElementById('hidden').setValue(pos);// save value
return app;// update app
}
The following piece of code is doing the same, but with the usage of a ScriptProperties method. Nothing fancy to it and works like a charm:
function doGet() {
var app = UiApp.createApplication();
// create listBox and add items
var listBox = app.createListBox().setName("myListBox")
.addItem("item 1")
.addItem("item 2")
.addItem("item 3");
// set position
ScriptProperties.setProperty('position', '0');
// create handle for button
var handler = app.createServerHandler("buttonHandler").addCallbackElement(listBox);
// create flexTable and button
var table = app.createFlexTable().setId("myTable");
var button = app.createButton("+", handler);
// add all to application
app.add(listBox)
.add(button)
.add(table);
// return to application
return app;
}
function buttonHandler(e) {
var app = UiApp.getActiveApplication();
// get position
var position = parseInt(ScriptProperties.getProperty('position'),10);
// get myTable and add
app.getElementById("myTable").insertRow(position).insertCell(position, 0).setText(position, 0, e.parameter.myListBox);
// increment position
var newPosition = position++;
// set position
ScriptProperties.setProperty('position', newPosition.toString());
// return to application
return app;
}
Please de-bug the code, so that the authorization process is initiated.
Reference: Script and User Properties

google apps script TextBox value not passed to e.parameter.TextBoxName

On the code below I am defining a TextBox with name and id. The button handler works fine but I am not been able to get the value entered on the TextBox. The msgBox shows up but the e.parameter.matchValue shows as undefined.
On other part of the app I have the same logic but with a ListBox and it works fine.
What am I doing wrong?
function chooseColumnValueToMatch() {
var app = UiApp.createApplication().setHeight(150).setWidth(250);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var columnName = ScriptProperties.getProperty("columnNameToMatch");
var h1Line = app.createHTML("<h2>Value to match "+columnName+":</h2>");
var textPara = app.createHTML("<p>Type the VALUE that the <b>"+columnName+"</b> column must match EXACTLY to send the message.</p>");
var selectionHandler = app.createServerHandler('chooseColumnValueToMatchSelectionHandler');
var valueInputBox = app.createTextBox()
.setTitle("Match value for "+columnName)
.setName("matchValue")
.setId("matchValue");
var submitBtn = app.createButton("Submit", selectionHandler);
app.add(h1Line)
.add(textPara)
.add(valueInputBox)
.add(submitBtn);
ss.show(app);
}
function chooseColumnValueToMatchSelectionHandler(e){
var app = UiApp.getActiveApplication();
var columnName = ScriptProperties.getProperty("columnNameToMatch");
var ss = SpreadsheetApp.getActiveSpreadsheet();
var msg = e.parameter.matchValue;
Browser.msgBox("Value to match "+columnName+" column is:", msg, Browser.Buttons.OK);
return app;
}
You have to use the ServerHandler.addCallbackElement method. The following code demonstrates it. The method call "tells" GAS internals that the value of the widget pointed as the parameter should be passed to the handler.
If you have multiple widgets, which should be handled by the handler, then, instead of calling the addCallbackElement with every widget, is possible to place all controls to a panel and point only the panel as the addCallbackElement method parameter. The code in the point 4.4 of this tutorial shows this way.
function doGet(e) {
var app = UiApp.createApplication();
var valueInputBox = app.createTextBox()
.setTitle("Match value for XXX")
.setName("matchValue")
.setId("matchValue");
var selectionHandler = app.createServerHandler('chooseColumnValueToMatchSelectionHandler');
selectionHandler.addCallbackElement(valueInputBox);
var submitBtn = app.createButton("Submit", selectionHandler);
var output = app.createLabel().setId("output");
app.add(valueInputBox).add(submitBtn).add(output);
return app;
}
function chooseColumnValueToMatchSelectionHandler(e){
var app = UiApp.getActiveApplication();
var output = app.getElementById("output");
var msg = e.parameter.matchValue;
output.setText("Value to match XXXX column is: " + msg);
return app;
}
It seems that you forgot to add a callbackElement to your handler
you could try like this :
selectionHandler.addCallbackElement(valueInputBox)
right after the submitBtn definition

using and modifying global variables within handler functions

Hello everyone out there,
I can use global variables within a handler function, however I cannot modify them "globally" within than function.
In code below, after the first click it will show the number 1001 (the handler reads, increments and shows the right result).
But, any further clicks will always show 1001, so the handler keeps reading the original globalVar value: it doesn't get modified as I was expecting.
Anything I can do to fix this?
var globalVar = 1000;
function testingGlobals() {
var app = UiApp.createApplication();
var doc = SpreadsheetApp.getActiveSpreadsheet();
var panel = app.createVerticalPanel().setId('panel');
app.add(panel);
panel.add(app.createButton(globalVar).setId("globalVar").addClickHandler(app.createServerHandler("chgGlobal").addCallbackElement(panel)));
doc.show(app)
}
function chgGlobal(e) {
var app = UiApp.createApplication();
globalVar++;
app.getElementById("globalVar").setText(globalVar);
return app;
}
You can not increment Global Variables this way, as every time a handler executes, Global variable is initialized and then manipulated.
You can use hidden formfields to hold the a variable which you can change in handler, and it will be persistent as long as the app is open.
e.g
function testingGlobals() {
var app = UiApp.createApplication();
var doc = SpreadsheetApp.getActiveSpreadsheet();
var panel = app.createVerticalPanel().setId('panel');
var myVar = app.createHidden().setValue('0').setName('myVar').setId('myVar');
panel.add(myVar);
app.add(panel);
panel.add(app.createButton('0').setId("globalVar").addClickHandler(app.createServerHandler("chgGlobal").addCallbackElement(panel)));
doc.show(app)
}
function chgGlobal(e) {
var app = UiApp.createApplication();
gloabalVar = parseInt(e.parameter.myVar);
gloabalVar ++;
app.getElementById('myVar').setValue(gloabalVar.toString());
app.getElementById("globalVar").setText(gloabalVar);
return app;
}
You can persist data in CacheService (fast but not guaranteed) or ScriptProperties or ScriptDb (a little slower, but persisted) instead of global properties. ScriptDb in particular can hold objects without needing to use strings to store them.

problems with setting parameters query objects

Why app.getElementById('myTextBox').setValue('default') work in showDialog() but didnt work in respondToSubmit(e)?
function showDialog() {
var app = UiApp.createApplication();
var panel = app.createVerticalPanel();
var textBox = app.createTextBox();
textBox.setName('myTextBox').setId('myTextBox');
app.getElementById('myTextBox').setValue('default');
var button = app.createButton(Modify');
panel.add(textBox);
panel.add(button);
var clickHandler = app.createServerClickHandler("respondToSubmit");
button.addClickHandler(clickHandler);
clickHandler.addCallbackElement(panel);
app.add(panel);
var doc = SpreadsheetApp.getActive();
doc.show(app);
}
function respondToSubmit(e) {
var app = UiApp.getActiveApplication();
app.getElementById('myTextBox').setText('Modifed');
}
Add
return app;
at the end of your respondToSubmit function
in one case you use setText(), in the other you use setValue() ... didn't you notice ?
Also, when you are in the same function where you create an element you don't need to use getElementById() you can just use textBox.setValue() since textBox is the variable that holds the element- the getElementById is only used to recall an element from another function.