I would like to edit the timing of a trigger based on a value in a cell of a spreadsheet. The only way I can think of is to set a trigger for a function that is deleting all triggers and making new triggers based on the value of a cell. Is there a way to edit the existing timing of existing triggers?
You can delete just one.
function deleteTrigger(funcName)
{
var triggers=ScriptApp.getProjectTriggers();
for(var i=0;i<triggers.length;i++)
{
if(funcName==triggers[i].getHandlerFunction())
{
ScriptApp.deleteTrigger(triggers[i]);
break;
}
}
}
I run things at variable time intervals by setting my trigger to the minimum interval I need, tying the trigger to a function that tests against criteria. If criteria is met, I execute the desired function. You could implement this principle where the criteria for whether to execute the main function is dependent on the cell contents (or direct it to different functions depending on the contents of the cell).
Related
I have a Google App Script function in a Google Sheets spreadsheet I need to call once a day using a time-driven trigger.
This function often takes longer to run than the maximum time allowed for scripts, currently 6 minutes, so I've written it to do its work over several calls. If the function hasn't finished I would like to create a temporary time-driven trigger to run the function again in one minute and delete the temporary trigger when the function is called, but leave the daily trigger active. Pseudocode probably explains it better...
function run_job_via_trigger(trigger) {
if(trigger === temporary trigger) {
// If this is a 'temporary' trigger that was created to
// run the job after the first call then delete it.
// This must not delete the daily trigger that makes the
// first call to the function.
// If I check the UID of the trigger here I still
// would need to know which trigger is the daily trigger
// and which is a temporary trigger!
ScriptApp.deleteTrigger(trigger)
}
const job_finished = job_that_takes_several_calls_to_complete();
if(job_finished === false) {
// Create a temporary time-driven trigger to call this
// function again in 1 minute.
ScriptApp.newTrigger('run_job_via_trigger').timeBased().everyMinutes(1).create();
}
}
function job_that_takes_several_calls_to_complete() {
// This function often takes more time to complete than
// the maximum time allowed for scripts to run. It keeps
// track of its execution time and returns true if it has
// finished doing what it needs to do or false if it
// needs more time and should be called again.
return finished ? true : false;
}
How can I detect which time-driven trigger has called the run_job_via_trigger function so I can delete the temporary trigger(s) but not the daily trigger?
The spreadsheet has several other time-driven triggers so simply deleting all triggers at the end and creating a new daily trigger is not, as far as I can tell, an acceptable solution.
When your function is called with a trigger, it receives a trigger event as its parameter. You can check the trigger UID for example, like so:
function doWhatever(e) {
if(e.triggerUid === 'trigger_id') {
// do something
} else {
// do something else
}
}
UPDATE
There are a couple of ways to know which triggers are running.
The best-case scenario, when you created a trigger, you stored its ID somewhere, like user properties and then you always know when it's running. But I guess you haven't done that.
In your case you might want to do some manual work. Go to the triggers page, find your recurring trigger, click on the three dots on the right and select "Executions". You will then see the trigger ID in the filter:
Now you can use that in your code to check whether it's your recurring trigger or your temporary trigger.
I have a function that copies rows from one sheet to another, which works when I run it manually:
function updateDataRange() {
var formSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Form Responses 1");
var lastFormRow = formSheet.getLastRow();
var dataSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("DataRange");
dataSheet.clear();
for(var rowCounter = 1; rowCounter <= lastFormRow; rowCounter++) {
var sourceRange = formSheet.getRange('B'+rowCounter+':H'+rowCounter);
var insertRow = dataSheet.getLastRow() + 1;
var targetRange = dataSheet.getRange('A'+insertRow);
sourceRange.copyTo(targetRange);
}
}
However, when I run this via a trigger (e.g. function onEdit(e) { updateDateRange(); } ), there are gaps in the rows and some of the values will be left out. In this case, I know there is a "fix" by using rowCounter instead of insertRow to write the files instead of using getLastRow(), but one can easily see how this is a problem in another scenario.
So I guess my question is simple: Why isn't this working correctly when using a trigger?
Edit: To clarify, I have a 3rd sheet with some conditions/cells (i.e. conditions that influence which rows are to be copied) and changing them (like changing a different date) trigger the function.
Explanation:
You are using an onEdit trigger to capture sheet changes. But onEdit triggers work only when the user changes the value of a cell. Referencing the official documentation:
The onEdit(e) trigger runs automatically when a user changes the value
of any cell in a spreadsheet.
In your case, I think you are trying to execute this code when the Form Responses sheet is filled in with data by the form.
There are two kind of trigger functions that work with form submissions and they are both installable.
One is a google sheet event based trigger and the other one a form event based trigger.
Your goal is to execute some code from the google sheets side, so it makes sense to use the first one.
Modifications:
Change the name of the function from onEdit to a different name of your choice e.g. myFormSubmitTrigger.
Since the trigger is installable you need to "install" a onFormSubmit trigger for the myFormSubmitTrigger function. Here you can find some simple instructions on how to do that.
If your question is why doesn't your function work when the form makes changes to sheet Form Responses 1 then Marios has answered you question accept it and move on. If your trying to run your function when a user is making edits to sheet Form Responses 1 using a simple trigger then a possible explanation for not getting all of the rows completely copied is that simple trigger must complete in 30 seconds. If you continue to accept more data in Form 1 Responses then soon or later you will have problems but with this function it will be a lot later because it will run much faster than your code:
function updateDataRange() {
const sss=SpreadsheetApp.openById('ssid');
const ssh=e.source.getSheetByName('Form Responses 1');
const sr=2;
const svs=ssh.getRange(sr,2,sh.getLastRow()-ssr+1,7).getValues();
const dsh=e.source.getSheetByName('DataRange');
dsh.clear();
dsh.getRange(1,1,svs.length,svs[0].length).setValues(svs);
}
However, I would recommend that you never edit a form responses sheet. I would consider using the onFormSubmit trigger to capture all of the data to a second sheet that is available to edit. And it will have additional data automatically appended to it via dsh.appendRow(e.values). And so now you would no longer require an onEdit trigger because your data sheet is kept upto data with an onFormSubmit trigger and you may feel free to edit the datasheet any time you wish.
If neither of these questions suffices then I would recommend that you be more clear about what you are asking.
Thanks in advance for your help ...
I need to run a script upon editing just a single cell in a specific sheet.
A new row is first appended to the bottom of the dataRange.
The user first selects a date from a datePicker in Col A and then selects an entry from a list (using Data Validation) in Col B.
The idea is to use the textFinder to find the first previous row that matches the selected list item in Col B so that other cells on the new row can be populated from the found matched row.
All is working well except for the trigger.
Any ideas on how to trigger the script would be gratefully received!
Answer:
You can use an onEdit(e) trigger containing a conditional which only executes if a certain cell has been edited.
Code:
You can run whatever script you like on the edit of a specific cell by first checking the range of the edit using the event object:
function onEdit(e) {
if (e.range == 'A1') {
// put the code you want to run here
}
// you can put additional else if statements here if you want other code to
// execute on other cells being edited
else {
return;
}
}
Make sure to run the script manually one time first so that you can authenticate!
References:
Simple Triggers
Event Objects
I have a function that updates a spreadsheet. It runs every morning and, every time it does, it creates 4 triggers.
I also have time-driven triggers, which I want to keep there.
Since there is a limit on the triggers, I need to remove the triggers created by the function (while maintaining the other ones). However, when I run this:
function Triggers () {
Logger.log(ScriptApp.getProjectTriggers())
}
I get this as a response:
[Trigger, Trigger, Trigger, Trigger, Trigger, Trigger, Trigger, Trigger]
How can I identify, of these, the ones created by that function so I can eliminate those only?
I used this code:
function Triggers () {
var triggers = ScriptApp.getProjectTriggers()
for (i in triggers)
if ((triggers[i].getHandlerFunction()) == "createStats") {
ScriptApp.deleteTrigger(triggers[i])
}
}
I need to get the row number and the content for the deleted row in onEdit trigger script. or is there an onDelete function?
Basically, when user deletes one row or a range of rows, the script should be notified the range deleted, in some way.
If user deletes one cell this works:
function onEdit(e) {
if (e.value==e.source.getActiveSheet().getActiveCell().getValue()) {
//Things to do for normal edition
} else {
//Things to do if cell was deleted
deleted_range = e.range
}
}
I'm not shure if that's the right solution but works fine until now. For multiple cells i can't find a solution yet :/
This is not possible. There's a feature request opened regarding this, you may want to star it to keep track of updates and kind of vote for it.
Issue 1363: Add trigger for spreadsheet column or row operations