How to define global variable in Google Apps Script
Asked Answered
M

8

68

I see most examples from Google is they use only functions in a single giant script.

e.g. https://developers.google.com/apps-script/quickstart/macros

But in our style, we usually write all functions under a single namespace, such as

MyCompany = (MyCompany || {});
MyCompany.init = function () {
    Logger.log('init');  
};

function onOpen() {
    var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
    var menus = [{
        name: "Init",
        functionName: MyCompany.init
    }];
    spreadsheet.addMenu("Test", menus);
};

However, when I run the code above, it return

"MyCompany is not defined."

How to solve?

Marge answered 13/7, 2014 at 9:23 Comment(3)
Have you tried using var: var MyCompany = (MyCompany || {});Rincon
Google apps script IS server side Javascript (maybe you know this). Also google apps script "resets" after every server call, so changes to variables are discarded.Quadripartite
I can confirm that using var works.Jozef
E
138

You might be better off using the Properties Service as you can use these as a kind of persistent global variable.

click 'file > project properties > project properties' to set a key value, or you can use

PropertiesService.getScriptProperties().setProperty('mykey', 'myvalue');

The data can be retrieved with

var myvalue = PropertiesService.getScriptProperties().getProperty('mykey');
Encomiastic answered 15/7, 2014 at 4:7 Comment(8)
Your answer worked perfectly for me I used "File > Project properties > Script properties". I then added a "Property" and a "Value" and then I used your "retrieved with" code. Very nice!Uncalledfor
Nice! thanks! this only stores strings, so I used json strings to store complex objects. :)Haematinic
Remember that setting such a global variable in your script won't trigger a re-execution of custom functions in spreadsheet cells. So you can't use a global variable to for instance have a cell in the spreadsheet automatically update based on reading that global variable.Cozy
Very useful solution for me.Morgenthaler
Currently setProperty and getProperty are deprecated. What is the modern way of doing that? Using a Cell to store the info?Stitch
@Stitch Google did not mark the methods as deprecated. Documentation here: developers.google.com/apps-script/guides/propertiesBijection
In the GUI, those so-called "Script Properties" are now in the Apps Script IDE at "Project Settings" (the Gear Icon on the left) at the bottom.Tetrabrach
Just to add to the value of the conversation Im struggling storing json String as @Haematinic did but, converting it back gives an error, since its storing the string in an odd maner, like: {data={key_people=[Ljava.lang.Object;@41c0e22b},...Carissacarita
A
13

In GAS global variables are not what they are in other languages. They are not constants nor variables available in all routines.

I thought I could use global variables for consistency amongst functions and efficiency as well. But I was wrong as pointed out by some people here at SO.

Global variable will be evaluated at each execution of a script, so not just once every time you run your application.
Global variables CAN be changed in a script (so they are not constants that cannot be changed by accident), but will be reinitialized when another script will be invoked.
There is also a speed penalty on using global variables. If within a function you use the same global variable two or more times, it will be faster to assign a local variable and use that instead.

If you want to preserve variables between all functions in your application, it might be using a cacheService will be best. I found out that looping through all files and folders on a drive takes a LOT of time. But you can store info about files and folders within cache (or even properties) and speed up at least 100 times.

The only way I use global variables now is for some prefixes and for naming widgets.

Arsenic answered 14/7, 2014 at 8:4 Comment(3)
I doubt performance is affected when using a global versus local. Please detail.Rubel
I'm referring to the answer and discussion by Serge Insas #24327024 I also saw another discussion at SO regarding local vs global variables. But haven't found it nowArsenic
Ok I see. But note the performance hit would be from calling code to initialize the variable, and not the fact that is a global or local.Rubel
C
12

I'm using a workaround by returning a function with an object of my global variables:

function globalVariables(){
  var variables = {
    sheetName: 'Sheet1',
    variable1: 1,
    variable2: 2
  };
  return variables;
}

function functionThatUsesVariable (){
  var sheet =   SpreadsheetApp.getActiveSpreadsheet().getSheetByName(globalVariables().sheetName);
}
Culliton answered 1/3, 2017 at 16:18 Comment(2)
This solution will not actually work as a global variable, since you cannot change the global "variable" by using for instance globalVariables().sheetName = 'Sheet2'. This is also the case if it was merely a seeming global variable like var global = { sheetName: 'Sheet1' }, since doing global.sheetName = 'Sheet2' inside a function will have no effect on that global variable, but merely create a local copy. Using the global variable in another function after that will not have picked up the change. See: https://mcmap.net/q/282073/-global-variables-in-google-script-spreadsheetCozy
This also works with declaring global const. Quite a trick!Stanislas
K
5

Global variables certainly do exist in GAS, but you must understand the client/server relationship of the environment in order to use them correctly - please see this question: Global variables in Google Script (spreadsheet)

However this is not the problem with your code; the documentation indicates that the function to be executed by the menu must be supplied to the method as a string, right now you are supplying the output of the function: https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet#addMenu%28String,Object%29

function MainMenu_Init() {
    Logger.log('init');  
};

function onOpen() {
    var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
    var menus = [{
        name: "Init",
        functionName: "MainMenu_Init"
    }];
    spreadsheet.addMenu("Test", menus);
};
Katharina answered 15/7, 2014 at 5:32 Comment(0)
V
2

I use this: if you declare var x = 0; before the functions declarations, the variable works for all the code files, but the variable will be declare every time that you edit a cell in the spreadsheet

Vasileior answered 24/1, 2019 at 2:6 Comment(0)
E
2

I needed something similar like the question, you can store and fetch from the cache https://developers.google.com/apps-script/reference/cache/cache

Example:

// call cache service
 var cache = CacheService.getScriptCache();
// get an item from the cache
  var cached = cache.get("somekey");
// if exists in the cache use it
  if (cached != null) {
   // use it whatever you like. 
  }else{
   // calculate/assign your data to cache
   cache.put("somekey","somevalueorobject");

  // you can even put cache data on TTL (time to live)  in seconds.
   cache.put("somekey","somevalueorobject",60);
Epiblast answered 19/11, 2021 at 22:48 Comment(0)
S
1

For constants I am using function arrow expressions. The footprint is similar to a variable declaration. Just add the () => when declaring, and () when calling the (function) variable.

var currentSheet = () => SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var maxAttempts = () => 10;

function myFunction(){
    var sheetName = currentSheet().getName();
    for (var i=0; i< maxAttempts(); i++){
        trySomething(i);
    }
}


Snazzy answered 14/1, 2022 at 3:4 Comment(0)
Z
0

Two teeny-tiny changes fix the "MyComany is undefined error" and a syntax error on the menus variable declaration.

  1. Assign directly an empty object instead of using the short-circuit object assignation on the MyCompany variable declaration
  2. The value assigned to the menu item functionName property should be a string.
MyCompany = {};
MyCompany.init = function () {
    Logger.log('init');  
};

function onOpen() {
    var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
    var menus = [{
        name: "Init",
        functionName: "MyCompany.init"
    }];
    spreadsheet.addMenu("Test", menus);
};

Another way to declare a namespace

const MyCompany = (ns => {
  ns.init = function () {
     Logger.log('init'); 
  return ns;
}({});

About Global Variables in Google Apps Script

Some previous answers have warned that global variables don't work as commonly expected based on experience working with JavaScript on other platforms.

The key is to understand that each call of the Google Apps Script function from a custom menu, Google Sheets image with an assigned function, dialog, sidebar or web application using the HTML Service, trigger, the Apps Script editor or the Google Apps Script API will load the whole Apps Script project into the Google Apps Script execution engine.

If you use the globally declared variables on a single execution, there should not be problems, as the code is written properly. However, if you need to keep the object and values assigned to the variables across multiple executions, then you have to save those values somewhere other than the runtime memory.

There are several options

  1. Properties Service.
  2. Cache Service.
  3. An external database using the JDBC Service
  4. A Google Sheets spreadsheet using the Spreadsheet or the Advanced Sheets services.
  5. A Google Drive file using the Drive or the Advanced Drive services.
  6. Etc.

Related

Zeke answered 30/6 at 15:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.