What I'm trying to achieve
I have a spreadsheet with 2 sheets A
& B
.
A
has 2 columns - Name, Amount (Master List)B
has 4 columns - Name, Amount, X, Y (Transaction List)
Name column of Sheet B
references Name column of Sheet A
for data. Whenever a name is selected, I want to populate Amount column in B
with Amount in column of sheet A
as a placeholder which users can override. For this, I plan to load the Sheet A
data in an array (available Globally) so that in onEdit(e)
I can refer that array instead of accessing Sheet B
.
But the options I could find - CacheService
and PropertyService
- save only string values. But I want to have:
var myGlobalArray = [];
function on init(){
//iterate and fill the array such that it has following output
//myGlobalArray[Name1] = 1
//myGlobalArray[Name2] = 2
//myGlobalArray[Name3] = 3
}
function onEdit(e){
//if selected value is name1, populate myGolbalArray[Name1] value in Amount
}
Question Where & how to define myGlobalArray?
I tried to use cache service with JSON.Stringify
and JSON.parse
but the array is empty in onEdit
.
Each call to your script creates a new instance of your script with its own unique globals. Every time you call a script you will actually find a global "this" for that specific instance. You are correct to look at PropertyService as a persistent way to save data.
Right off I See that your globalArray is not set up right:
needs to be
Now that can be saved to and read from the property store.
It's true that CacheService and PropertyService save only string values, but you can store any scalar data by using the
JSON
utilitiesJSON.stringify()
andJSON.parse()
.When a variable is called "Global", we are referring to its scope, saying that it is available to all code within the same module. (You can read more about scope in What is the scope of variables in JavaScript?)
But since you're looking at CacheService and PropertyService, you already know that scope is only part of the problem. Each time that
onEdit()
is invoked, it will be running in a new execution instance on one of Google's servers. A value that had been in a global variable in a previous instance will not be available to this new instance. Therefore, we need to populate our "global variable" in each new invocation of our script.An elegant way to reference global variables is as names properties of the special
this
object. For example, every function in our script can refer tothis.myGlobalArray
.1You can adapt the
getRssFeed()
example from the Class Cache documentation intoget_myGlobalArray()
, say. Then youronEdit()
trigger needs only to call that first to make sure thatthis.myGlobalArray
contains the relevant array data.Edit: Associative Array
In the comment within
onEdit()
, it's indicated:This implies that
myGlobalArray
is an associative array, where the index is a non-integer value. This requirement is now reflected in the way thatthis.myGlobalArray
gets populated when read from the spreadsheet.Much has been written about the different flavours of Javascript arrays, for instance Javascript Associative Arrays Demystified.
1 Actually, only functions with global scope would understand
this
to mean "global to the script". Functions that are contained inside objects would interpretthis
to mean their host object only. But that's a story for another day.