Consider this –
the script
1 2 3 4 5 6 7 8 9 |
function doGet(e) { return HtmlService .createTemplateFromFile('mytemplate') .evaluate(); } function getValue() { return 'hello world'; } |
the template
1 2 3 4 5 |
<script> google.script.run.withSuccessHandler(function (value) { alert (value); } ).getValue(); </script> |
I get a correct hello world alert.
So now let’s try amending the script like this
1 2 3 4 5 6 7 8 9 10 |
var global = "hello world"; function doGet(e) { return HtmlService .createTemplateFromFile('mytemplate') .evaluate(); } function getValue() { return global; } |
It still works.
How about this.
1 2 3 4 5 6 7 8 9 10 11 |
var global; function doGet(e) { global = "hello world"; return HtmlService .createTemplateFromFile('mytemplate') .evaluate(); } function getValue() { return global; } |
This time I get undefined instead of ‘hello world’.
What’s going on ?
When you execute google.script.run() on the server, it initiatializes the script again. This means that any global variables are reinitialized each time. In other words – a global variable only retains its value inside the instantiation of its script. In the first case the same value would have been set as before – since it’s outside any function and would have been re-executed. In the second case, doGet() would have needed to be executed to give the variable a value. Since it is not, the variable remains as undefined.
This makes it fairly tricky to do things like pass parameters received by doGet(e) to a script running on the client-side. Approaches to this might be to use the propertyService, or perhaps the cacheService for when the call from google.script.run comes.
In some cases though, it’s not necessary. Here’s the approach I use (which avoids the call back to the server from the client script altogether).
My script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
function doGet(e) { var data = {text:"hello world"}; // get the template var html = HtmlService .createTemplateFromFile('mytemplate') .evaluate() .getContent(); // now pass the data via a script return HtmlService .createTemplate(html + "<script>\n" + "doIt( " + JSON.stringify(data) + ");\n</script>") .evaluate(); } [su_spacer size="10"] My template <script> function doIt(data) { alert (data.text); } </script> |
Using this method, we don’t need any global variables that would need reinitializing, because we evaluate a template that already contains the embedded variable data from the main script.
Explanation
Here’s the data we need to get to the client-side script.
1 |
var data = {text:"hello world"}; |
The client script wants to do something with it – so we wrap the scripted actions in a function that expects its data as an argument.
1 2 3 4 5 |
<script> function doIt(data) { alert (data.text); } </script> |
Evaluate that template as normal, but get its content
1 2 3 4 5 |
// get the template var html = HtmlService .createTemplateFromFile('mytemplate') .evaluate() .getContent(); |
Append the data right in your evaluated template, and include a call to the script that does the work. The data will actually be written as part of the script, then evaluate the whole thing.
1 2 3 4 5 6 7 8 |
// now pass the data via a script return HtmlService .createTemplate(html + "<script>\n" + "doIt( " + JSON.stringify(data) + ");\n</script>") .evaluate(); |
Here’s what the overall evaluated script that HtmlService will finally execute, and why it works.
1 2 3 4 5 6 7 8 9 |
<script> function doIt(data) { alert (data.text); } </script> <script> doIt( {"text":"hello world"}); </script> |