Ryan
Ryan

Reputation: 10101

How to define global variable in Google Apps Script

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?

Upvotes: 71

Views: 163873

Answers (8)

Wicket
Wicket

Reputation: 38200

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

Upvotes: 1

ΞΫΛL
ΞΫΛL

Reputation: 194

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


Upvotes: 1

Kambaa
Kambaa

Reputation: 485

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

Upvotes: 2

AshClarke
AshClarke

Reputation: 3078

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');

Upvotes: 142

KrzFra
KrzFra

Reputation: 159

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

Upvotes: 13

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

Upvotes: 2

Tim
Tim

Reputation: 766

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

Upvotes: 5

SoftwareTester
SoftwareTester

Reputation: 1090

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.

Upvotes: 13

Related Questions