GAS: How to change a global variable value and pre

2020-05-09 01:16发布

问题:

I have this global variable in my script:

var targetDocId = 'No doc ID informed yet';

I'm trying to change the value of this global variable inside my main function:

function generatePersonDatasheet() {
  var target = createDuplicateDocument(template, docName);
  var link = target.getUrl();
  targetDocId = target.getId(); // <-------- HERE
  if (theses == 1){
    Logger.log("going to showList() ");
    return showList();
  }   
  showURL(docName, link); 
}

After that, I'm trying to acess the changed global variable value in a handler function:

function submit(e){
  var numberOfItems = Number(e.parameter.checkbox_total);
  var thesesArrays = [];
  for(var i = 0; i < numberOfItems; i++){
    if(e.parameter['checkbox_isChecked_'+i] == 'true'){
      thesesArrays.push(fact_list[i]);
    }
  }
  for (var i = 0; i < thesesArrays.length; i++){
    var thesesId = thesesArrays[i][2];
    var thesesType = thesesArrays[i][1];        
    importTheses(targetDocId, thesesId, thesesType); // <-----HERE
  }
  return UiApp.getActiveApplication().close();
}

function importTheses(targetDocId, thesesId, thesesType) {
  var targetDoc = DocumentApp.openById(targetDocId);
  var targetDocParagraphs = targetDoc.getParagraphs();
  var targetDocElements = targetDocParagraphs.getNumChildren();

  var thesesDoc = DocumentApp.openById(thesesId);
  var thesesParagraphs = thesesDoc.getParagraphs();
  var thesesElements = thesesDoc.getNumChildren();

  var eltargetDoc=[];
  var elTheses=[];

  for( var j = 0; j < targetDocElements; ++j ) {
       var targetDocElement = targetDoc.getChild(j);
        eltargetDoc[j]=targetDocElement.getText();
       if(el[j]== thesesType){
           for( var k = 0; k < thesesParagraphs-1; ++k ) {
               var thesesElement = thesesDoc.getChild(k);
               elTheses[k] = thesesDoc.getText();
               targetDoc.insertParagraph(j, elTheses[k]);
         }
      }
   }
}

But, as long as I tryied to change the targetDocId, when it's use as argument to importTheses(targetDocId, thesesId, thesesType); it still has the value 'No doc ID informed yet', even I have changed it, as if the program had been run from the beginning. Is an alternative to this "reset to original value" behavior? Or I have to use scriptDB or ScriptProperties to store the changed value of the global variable?

回答1:

Each separate execution of a script is done in a new execution instance. Any variables defined outside of a block of code (aka "global" variables) are therefore unique for that instance. When a trigger function is invoked by an event, it runs in its own instance, and any global values it sets are visible only to that instance; another function that is invoked by a spreadsheet or document UI, for example, would have its very own version of that non-scoped object (global).

Definition and retrieval of targetDocId would be a good application of the Cache Service.note

function get_targetDocId () {
  var cache = CacheService.getPublicCache();
  var cached = cache.get("targetDocId");
  if (cached != null) {
    return cached;
  }
  var target = createDuplicateDocument(template, docName);  /// Need to add handling for pre-existing document
  var link = target.getUrl();
  var contents = target.getId();
  cache.put("targetDocId", contents, 1500); // cache for 25 minutes
  return contents;
}

Now instead of trying to use a global variable, just call this function:

...
var targetDoc = DocumentApp.openById(get_targetDocId());
...

note Cache Service is one example of persistent storage available for Google Apps Script. The Properties Service was introduced after this answer was written, and is a much lighter-weight way to persist "global" variables between execution instances.


Observation: it appears that you're using a global (static) for tempate and docName, since there are no parameters for generatePersonDatasheet(). You could simply generate the targetDocId on the fly.

Bug: As it is written, get_targetDocId() will create a new copy of docName every time it needs to refresh the cache (15 mins). You should add handling for the possibility of a pre-existing file. (This is true of your existing onOpen() as well.)



回答2:

No theres no such option. You have to use scriptProperties or scriptDb. A global vsriable goes out of scope once your function finishes. Each outside script call starts from zero.