Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass a parameter to a time-based Google App Script trigger?

In my script, I am reading data from a Spreadsheet and creating a time based trigger to make a POST request with some of that data at a specific time.

The problem is, I can't find any way to pass the data to the function that is called by the trigger. All that the Google App Script doc offers is the ability to name the function to call, but no way to pass it parameters.

 var triggerDay = new Date(2012, 11, 1);
 ScriptApp.newTrigger("makePostRequest")
   .timeBased()
   .at(triggerDay)
   .create();

Does anyone know how I can pass makePostRequest parameters so the function will execute with the needed data?

like image 964
CodyBugstein Avatar asked Sep 21 '15 14:09

CodyBugstein


3 Answers

This is possible but requires multiple steps. The most important thing here are event objects (mentioned by @St3ph).

var RECURRING_KEY = "recurring";
var ARGUMENTS_KEY = "arguments";

/**
 * Sets up the arguments for the given trigger.
 *
 * @param {Trigger} trigger - The trigger for which the arguments are set up
 * @param {*} functionArguments - The arguments which should be stored for the function call
 * @param {boolean} recurring - Whether the trigger is recurring; if not the 
 *   arguments and the trigger are removed once it called the function
 */
function setupTriggerArguments(trigger, functionArguments, recurring) {
  var triggerUid = trigger.getUniqueId();
  var triggerData = {};
  triggerData[RECURRING_KEY] = recurring;
  triggerData[ARGUMENTS_KEY] = functionArguments;

  PropertiesService.getScriptProperties().setProperty(triggerUid, JSON.stringify(triggerData));
}

/**
 * Function which should be called when a trigger runs a function. Returns the stored arguments 
 * and deletes the properties entry and trigger if it is not recurring.
 *
 * @param {string} triggerUid - The trigger id
 * @return {*} - The arguments stored for this trigger
 */
function handleTriggered(triggerUid) {
  var scriptProperties = PropertiesService.getScriptProperties();
  var triggerData = JSON.parse(scriptProperties.getProperty(triggerUid));

  if (!triggerData[RECURRING_KEY]) {
    deleteTriggerByUid(triggerUid);
  }

  return triggerData[ARGUMENTS_KEY];
}

/**
 * Deletes trigger arguments of the trigger with the given id.
 *
 * @param {string} triggerUid - The trigger id
 */
function deleteTriggerArguments(triggerUid) {
  PropertiesService.getScriptProperties().deleteProperty(triggerUid);
}

/**
 * Deletes a trigger with the given id and its arguments.
 * When no project trigger with the id was found only an error is 
 * logged and the function continues trying to delete the arguments.
 * 
 * @param {string} triggerUid - The trigger id
 */
function deleteTriggerByUid(triggerUid) {
  if (!ScriptApp.getProjectTriggers().some(function (trigger) {
    if (trigger.getUniqueId() === triggerUid) {
      ScriptApp.deleteTrigger(trigger);
      return true;
    }

    return false;
  })) {
    console.error("Could not find trigger with id '%s'", triggerUid);
  }

  deleteTriggerArguments(triggerUid);
}

/**
 * Deletes a trigger and its arguments.
 * 
 * @param {Trigger} trigger - The trigger
 */
function deleteTrigger(trigger) {
  ScriptApp.deleteTrigger(trigger);
  deleteTriggerArguments(trigger.getUniqueId());
}

function example() {
  var trigger = ScriptApp.newTrigger("exampleTriggerFunction").timeBased()
    .after(5 * 1000)
    .create();

  setupTriggerArguments(trigger, ["a", "b", "c"], false);
}

function exampleTriggerFunction(event) {
  var functionArguments = handleTriggered(event.triggerUid);
  console.info("Function arguments: %s", functionArguments);
}

In case you are using the script properties for other values as well you might have to nest the trigger values.

Additionally you might have to use the script lock to prevent concurrent modification of the script properties.

like image 140
Marcono1234 Avatar answered Sep 18 '22 16:09

Marcono1234


You can't pass a parameter when a function is launched from a trigger.

You have to store this information somewhere to allow script find it. For example with what you say I understand you have some data in a spreadsheet, you can put this information in the spreadsheet. The function will manage the way to find appropriate information depending time it is fired.

Stéphane

like image 32
St3ph Avatar answered Sep 18 '22 16:09

St3ph


I'm not sure if it would address your specific issue, but the most convenient workaround I've found is to have a function with parameters wrapped in a function with no parameters, and then get the parameters from a static variable that you set in the top level of your script.

You still have to set the values within the script, but at least you can keep the logic separate so that you can use the base function with different values.

function functionAToTrigger(){
  functionToTriggerWithParams(myAParams);
}
var myAParams = {
  url: 'https://aurl.com',
  date: new Date(2012, 11, 1)
};
function functionBToTrigger(){
  functionToTriggerWithParams(myBParams);
}
var myBParams = {
  url: 'https://burl.com',
  date: new Date(2017, 11, 1)
};
function functionToTriggerWithParams(myParams){
   // Add some code to run some checks
   // Add some code here to log the results
}
ScriptApp.newTrigger(functionAToTrigger).timeBased().everyMinutes(10).create();
ScriptApp.newTrigger(functionBToTrigger).timeBased().everyMinutes(10).create();
like image 43
Rebecca Avatar answered Sep 20 '22 16:09

Rebecca