Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

google apps script - How to create a new clock trigger on another document

I have 30+ users each with their own spreadsheet. Each user's bound script references a custom library script that I use to keep my code centralized and easy to update.

I'm trying to use apps script to create triggers that run a specific function at a specific time. However, I can't figure out how to specify which script document the clock trigger is installed on.

Here's what I tried first:

createTimeTrigger("sendTimesheetsToHeads",1440);

function createTimeTrigger(functionToRun,minutesToWait) {
  ScriptApp.newTrigger(functionToRun)
  .timeBased()
  .at(new Date(new Date().getTime()+minutesToWait*60*1000))
  .create();
}

The above code is in the library file, but since the user is running the code, it installs the trigger on the user's container-bound script file, and not the library file. When the trigger runs, it fails because the trigger uses a function in the library that the user doesn't have direct reference to.

I need to be able to install the trigger programmatically on the independent library script file just like I can do manually. So after reviewing the apps script documentation (https://developers.google.com/apps-script/reference/script/trigger-builder#forDocument(String)), I found the forDocument() function for the trigger builder and tried this:

createTimeTrigger("sendTimesheetsToHeads",1440);

function createTimeTrigger(functionToRun,minutesToWait) {
  ScriptApp.newTrigger(functionToRun)
  .forDocument(<library script id here>)
  .timeBased()
  .at(new Date(new Date().getTime()+minutesToWait*60*1000))
  .create();
}

But the above code produces the following error: "TypeError: Cannot find function timeBased in object DocumentTriggerBuilder."

So then I tried switching the order around:

function createTimeTrigger(functionToRun,minutesToWait) {
  ScriptApp.newTrigger(functionToRun)
  .timeBased()
  .at(new Date(new Date().getTime()+minutesToWait*60*1000))
  .forDocument(<library script id here>)
  .create();
}

And received this error: "TypeError: Cannot find function forDocument in object ClockTriggerBuilder." It looks like the forDocument() and timeBased() functions are incompatible in the trigger builder?

Is it possible to do what I'm asking with apps script?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Please, take a look at the TriggerBuilder reference again - your function createTimeTrigger() should create two triggers, one with timeBased() and the other with forDocument(). Both methods, when invoked, return different class instances - ClockTriggerBuilder and DocumentTriggerBuilder respectively (so, the answer to your first question is - yes, they are incompatible.

Wrapper function

First approach assumes you have access to user document's apps script project or can otherwise add the wrapperInDoc() function to the document (this solution is retained in case someone needs it):

  1. the user to run your library script yourLib.createTimeTrigger();
  2. the time-based trigger to be installed on user document;
  3. the time-based trigger to fire a function in library;

Your library function should create a trigger to run wrapper function with a name common for all user documents that references target function in your library. Like so:

Library-scoped sample

function createTimeTrigger(functionToRun,minutesToWait) {
  ScriptApp.newTrigger('wrapperInDoc').timeBased().at(yourCond).create();
}

function wrapperInLib() {
  sendTimesheetsToHeads(); //function calls go here;
}

Document-scoped sample

function wrapperInDoc() {
  yourLib.wrapperInLib();
}

Self-calling library

As clarified in comments, you want:

  1. the user to run your library script yourLib.createTimeTrigger();
  2. createTimeTrigger() to install the time-based trigger on yourLib;
  3. the time-based trigger to fire a function in library;

Container-bound sample

function testLib() {
 var r = PG.createTimeTrigger(); //PG is how I named lib in my project;
 //do anything else;
}

Library sample

I set an arbitrary offset of 1 minute from "now" to trigger, just create your trigger as needed. Also, make sure that your script is published as a WebApp and anyone, even anonymous access is set on it (which should be ok as you use it as a library). You should use deployment Url for the fetch (the one with /exec).

/**
 * Runs on a get request;
 * @param {Object} e event object;
 * @returns {Content} text output to conform to being a web app;
 */
function doGet(e) {
  createTrigger();
  return ContentService.createTextOutput('success!');
}

/**
 * Self-run library project;
 */
function createTimeTrigger() {
  UrlFetchApp.fetch('yourLibraryUrl');
}

/**
 * Create trigger on self;
 */
function createTrigger() {
  var tr = ScriptApp.newTrigger('doSomething');
      tr.timeBased().at(new Date(new Date().valueOf()+60000)).create();
}

/**
 * Actual trigger callback;
 */
function doSomething() {
  //do something;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...