问题
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?
回答1:
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):
- the user to run your library script
yourLib.createTimeTrigger()
; - the time-based trigger to be installed on user document;
- 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:
- the user to run your library script
yourLib.createTimeTrigger()
; createTimeTrigger()
to install the time-based trigger onyourLib
;- 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;
}
来源:https://stackoverflow.com/questions/56363808/how-to-create-a-new-clock-trigger-on-another-document