Labs‎ > ‎

GAS, Persistent Variable over Events

posted May 30, 2011, 11:06 AM by Sundew Shin   [ updated May 30, 2011, 5:45 PM ]
The GAS platform does not provide such as persistent runtime memory equipment during the lifetime of an app: from the UI initialization (, and user interactions, and) to the termination of application. (closing the browser)

It seems on the surface the global variable declaration looks valid over all local scopes (functions) as the standard JS defines, but in effect, it will not be for eventhandlers because each invocation will reload the entire code on a brand-new copy of runtime memory (this is probably why it is so slow..), and all the states of the previous run will be inaccessible, as the following sample code will display ‘2’ on the textbox for button clicks all the time:

(cannot see the demo? click here )

Code

var app = UiApp.createApplication();
app.add(app.loadComponent('MyGui'));
function doGet(){return app;};

var global = 1;
app.getElementById('txtResult').setText(global + '');

function add(e){
  var app = UiApp.getActiveApplication();
  global++;
  app.getElementById('txtResult').setText(global + '');
  return app;
};

I wish GAS team elaborates this and at least document it for saving any further brain burns.
One way-around I found for making any states (values or objects, stringified) persistent over events is that saving it somewhere on the active UI. It will make your code strange but it will be cheaper than backup/restore the values using a spreadsheet for each invokes.

(cannot see the demo? click here )

Code

var app = UiApp.createApplication();
app.add(app.loadComponent('MyGui'));
function doGet(){return app;};

var btnAdd = app.getElementById('btnAdd');
var txtResult = app.getElementById('txtResult').setName('txtResult');
var pnlContainer = app.getElementById('pnlContainer');
// forward the click event to its container
btnAdd.addClickHandler(app.createServerClickHandler('add').addCallbackElement(pnlContainer));

var global = 1;
app.getElementById('txtResult').setText(global +'');

function add(e){
  var app = UiApp.getActiveApplication();
  global = new Number(e.parameter.txtResult);
  global++;
  app.getElementById('txtResult').setText(global + '');
  return app;
};



Update:
As Johninio pointed out in the original post, the proposed method can be elaborated as the following:

The idea of saving some state in the UI using hidden fields is an excellent on and one which I have used. There is nothing strange about it. If you want to make it interesting, create TextBox and set its visibilty to false. Then save your state information to an object and use Utilities.jsonStringify() to turn that to text and set your hidden TextBox to that. To reload the state you do something like this in your handler:

Code

function handler(e) {
  ...
  // load state
  var myState = Utilities.jsonParse(e.parameter.hiddenState);
  ...
  // do stuff possibly changing state, e.g.
  myState.selectedTab = 2;
  myState.counter += 1;
  ...
  // now save state to UI before returning
  app.getElementById("hiddenState").setValue(Utilities.jsonStringify(myState));
  return app;
}

tag:script | tag:programming | tag:demo
Comments