Declaring Global variables in Google Apps Script

 

Declaring Global variables in Google Apps Script

If you are codding on Google Apps Script environment you may have noticed that, as the code executed needs to live inside a function there is no way to declare Global Variables that can be executed all across the Script.

In the “compilation” process you always choose which function to run, so passing variables from one function to other can be tricky.

Below you can see the cleanest way I have found.

Properties Service Overview

For that we need to understand the PropertiesService In a nutshell this service lets you store some data in the form of Strings , that can be retrieved in further executions of the script, and all across the code that is written for that Script, this will give us: - Global like data storage - Persistant data storage

In a nutshell we can find the signatures of the methods for this service by

w3m --dump https://developers.google.com/apps-script/reference/properties

My notes look something like this I usually dump this signatures and add a -------(X) so when scrolling down my notes I can easily recall what methods I have already used

PropertiesService
PropertiesService.WHATEVERMETHOD

Methods

       Method           Return                 Brief description
                         type
PropertiesService.getDocumentProperties            Gets a property store (for this script only)  ------(X)
()                    Properties that all users can access within the open    FOR SOME REASON I CANNOT USE IT NULL
                                 document, spreadsheet, or form.
PropertiesService.getScriptProperties() Properties Gets a property store that all users can      ------(X)
                                 access, but only within this script.
PropertiesService.getUserProperties()   Properties Gets a property store that only the current   -----(X)
                                 user can access, and only within this script.

      Method          Return                  Brief description
                       type
propertiesRef.deleteAllProperties() Properties Deletes all properties in the current Properties   ---------(X)
                             store.
propertiesRef.deleteProperty(key) Properties Deletes the property with the given key in the    ---------(X)
                               current Properties store.
propertiesRef.getKeys()           String[]   Gets all keys in the current Properties store.
propertiesRef.getProperties()     Object     Gets a copy of all key-value pairs in the       ---------(X)
                               current Properties store.
                               Gets the value associated with the given key in
propertiesRef.getProperty(key)    String     the current Properties store, or null if no such  ---------(X)
                               key exists.
propertiesRef.setProperties(propertiesObject)Properties Sets all key-value pairs from the given object--------(X)
                                 in the current Properties store.
propertiesRef.setProperties                  Sets all key-value pairs from the given object
(propertiesObject,        Properties in the current Properties store, optionally
deleteAllOthers)               deleting all other properties in the store.
propertiesRef.setProperty(key, value) Properties Sets the given key-value pair in the current        -------(X)
                         Properties store.

Initiating the Properties Service

I prepended the propertiesRef. to the children methods of the Properties.

So easily we iniciate the service like this

function main () {
	var propertiesRef = PropertiesService.getScriptProperties();
}

Storing Properties

We can check then write a certain property, then Log it

function main () {
	var propertiesRef = PropertiesService.getScriptProperties();
	propertiesRef.setProperty('MY_VAR' , 'whateverValue');
	Logger.log(propertiesRef.getProperty('MY_VAR'));
}

Problem with undeclared properties

The issue is if you are trying to Access a property that doesn’t exists yet. It will throw out a null as its value. But I have found sometimes that we can get compilation errors as well when handling this.

function main () {
	var propertiesRef = PropertiesService.getScriptProperties();
	Logger.log(propertiesRef.getProperty('MY_VAR2'));
}
// Output : null

So I would make sure to initiate the property beforehand if it doesnt exists with a false value. Although remember that false would be parsed as a string.

function main(){
    var propertiesRef = PropertiesService.getScriptProperties();
    propertiesRef.getProperty('MY_VAR') ? 0 : propertiesRef.setProperty('MY_VAR' , 'false');
}

Problem with string datatype

Remember that false is a string value, if you wanted to perform some logic with it you would have to had it into consideration. For instance the next isolated line of code will show you how to store a true/false value , or any other.

propertiesRef.setProperty('MY_VAR' , sheetRef.getRange(2 , columnRef).getValue().toString());

Using Properties as Global Variables

Finally you can then share some data between functions the following way.

function main(){
    var propertiesRef = PropertiesService.getScriptProperties();
    propertiesRef.getProperty('MY_VAR') ? 0 : propertiesRef.setProperty('MY_VAR' , 'false');

    functionOne();
    Logger.log(propertiesRef.getProperty('MY_VAR'));
}
function functionOne () {
    var propertiesRef = PropertiesService.getScriptProperties();
    propertiesRef.getProperty('MY_VAR') ? 0 : propertiesRef.setProperty('MY_VAR' , 'false');
    /*
        SOME CODE HERE
    */
    propertiesRef.setProperty('MY_VAR' , 'true');

}

Appendix: Property Keys Naming Convention

All the code I have seen written online name the property Keys with Uppercase letters spaced by an underscore. As the engine is case sensitive, I don’t see why the reason to not to use the same convention as your variables, meaning camelCase, this way it will be easier to edit chunks of code with regexp

Therefore we can finally have

function main(){
    var propertiesRef = PropertiesService.getScriptProperties();
    propertiesRef.getProperty('myVar') ? 0 : propertiesRef.setProperty('myVar' , 'false');

    functionOne();
    Logger.log(propertiesRef.getProperty('myVar'));
}
function functionOne () {
    var propertiesRef = PropertiesService.getScriptProperties();
    propertiesRef.getProperty('myVar') ? 0 : propertiesRef.setProperty('myVar' , 'false');
    /*
        SOME CODE HERE
    */
    propertiesRef.setProperty('myVar' , 'true');

}

Conclusion

May not be the most orthodox solution to our scoping problems, but at least is a solution I have found, and just wanted to share it with you to gain some kudos in my life.