Reuse of google form triggers - google-apps-script

I automatically create a form with GAS as follows:
var form = FormApp.create(form_name);
ScriptApp.newTrigger('mysubmit')
.forForm(form)
.onFormSubmit()
.create();
The problem is that it creates a trigger every time new form is created.
Is there a way to reuse the same trigger? A problem is that a number of triggers available to my account runs out very quickly.

If you use an Apps Script to create a Form and then create a form submit trigger for that Form, the trigger you have created is attached to the script, not the new Form. This is why you are running into the 20 triggers / user / script quota limit.
Keep in mind that triggers live on scripts, not Docs, Sheets, or Forms. You can use a script to create a new Form, but you can't use a script to create a new script attached to that Form (scripts cannot create other scripts). This means you cannot programmatically create a trigger that lives on another document.
What you can do is create a Forms add-on that, when a new Form is created, a user can hit a menu control to create a form submit trigger for that Form.

My workaroung but still 20 triggers limit exists
function install_submit_trigger(form, fids)
{
var allTriggers = ScriptApp.getProjectTriggers();
for(var i = 0; i < allTriggers.length; i++)
{
ScriptApp.deleteTrigger(allTriggers[i]);
}
for(var i in fids)
{
var fid = fids[i];
try
{
ScriptApp.newTrigger('mysubmit')
.forForm(FormApp.openById(fid.fid))
.onFormSubmit‌​().create();
}
catch(e)
{
Logger.log("Error adding trigger: " + e);
}
}
ScriptApp.newTrigger('mysubmit') .forForm(form) .onFormSubmit() .create();
}

Related

Install user specific onEdit Trigger using Google Apps Script

I have created a simple OnOpen add-on in Google sheets that installs a trigger to send email based on Edit in the sheet. When I installed it, I authorized it from my account. The script is as follows:
function onOpen(e) {
var ui = SpreadsheetApp.getUi().createMenu("Install Trigger").addItem("Run", "initialize").addToUi();
}
const initialize = () => {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ScriptApp.newTrigger('sendEmail')
.forSpreadsheet(ss)
.onEdit()
.create();
};
The script runs fine and sends emails from my email address which I authorized. Now the issue is when I shared this sheet with another editor, the person does not need to install this trigger and he can send email from my email account without any authorization. Is there a way that we can make every editor in this sheet install their own trigger to send email from their email account instead of using mine?
You could use the method getUserTriggers(spreadsheet) that retrieves all installable triggers owned by the user executing the script:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var triggers = ScriptApp.getUserTriggers(ss);
// Log the event type for the first trigger in the array.
Logger.log(triggers[0].getEventType());
If this comes with a trigger, you know that the user has already installed the trigger.
If this comes empty, means that the user has no triggers in it. Then you could use the method deleteTrigger(trigger) to delete the existing triggers (created by others) in the script and then programatically create a new one:
var triggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < triggers.length; i++) {
ScriptApp.deleteTrigger(triggers[i]);
}

Create a trigger that works if the person is not an editor

I want people to jump to the current date row when opening the sheet. However, this should be the case for everyone viewing the sheet and irrespective of their edit-rights. For example, I want that people edit the current date row in the sheet every day over the link. In this case, onOpen() does not work. Is there any alternative or modification to the function?
I am informed about onOpen trigger, however, this would not work if somebody is editing the sheet only over the link with edit rights.
This is e.g. the code I would like to work for everyone:
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getRange("B:B");
var values = range.getValues();
var day = 24*3600*1000;
var today = parseInt((new Date().setHours(0,0,0,0))/day);
var ssdate;
for (var i=0; i<values.length; i++) {
try {
ssdate = values[i][0].getTime()/day;
}
catch(e) {
}
if (ssdate && Math.floor(ssdate) == today) {
sheet.setActiveRange(range.offset(i,0,1,1));
break;
}
}
}
I found the options: Edit Triggers
To manually create an installable trigger through a dialog in the script editor, follow these steps:
From the script editor, choose Edit > Current project's triggers.
Click the link that says: No triggers set up. Click here to add one now.
Under Run, select the name of function you want to trigger.
Under Events, select either Time-driven or the Google App that the script is bound to (for example, From spreadsheet).
Select and configure the type of trigger you want to create (for example, an Hour timer that runs Every hour or an On open trigger).
Optionally, click Notifications to configure how and when you are contacted by email if your triggered function fails.
Click Save.
Google Explanation to Edit Triggers

One time fire trigger?

When I first started coding in GAS I was using time based triggers and then deleting them when I started the next iteration (to get around time limits). I have since seen someone use a trigger that fires just once so I don't have to worry about deleting it, but I can't seem to find that example.
Old way:
//- This function deletes the running triggers from the repository creation process. it does NOT delete the form or
//- timed run triggers
function deleteTrigger() {
Logger.log("Deleting Triggers?");
// Loop over all triggers and delete them
var allTriggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < allTriggers.length; i++) {
var id = allTriggers[i].getHandlerFunction();
Logger.log(id);
if (id == "callCopy"){ScriptApp.deleteTrigger(allTriggers[i]); Logger.log("I deleted the copy files trigger");}
}
}
//This is the trigger to restart the call copy script in the right place.
function createTrigger() {
// Trigger every 1 minute
Logger.log("Creating File Copy Trigger");
ScriptApp.newTrigger('callCopy')
.timeBased()
.everyMinutes(1)
.create();
}

Using onChange trigger on google sheets script

I am running a script in google sheets script editor, to trigger the script I use onChange in the Current project's triggers, using specific function -> From Spreadsheet -> On change.
Important to mention that I use the sheet with 3 more members that have edit permission who change time to time the data, I built the script and activate the trigger.
When I change anything in the sheet I get alerted (the trigger were on) but when other member changes the data the trigger doesn't work.
What have I missed here?
Thanks.
Everyone needs a trigger
You can add the trigger management into the program so that they have the triggers in their projects too. The isTrigger() function insures that you only create one trigger for each instance. You find the documentation here.
function myTriggerSetup()
{
if(!isTrigger('functionName'))
{
ScriptApp.newTrigger('functionName').forSpreadsheet('Spreadsheet').onChange().create();
}
}
function isTrigger(funcName)
{
var r=false;
if(funcName)
{
var allTriggers=ScriptApp.getProjectTriggers();
var allHandlers=[];
for(var i=0;i<allTriggers.length;i++)
{
allHandlers.push(allTriggers[i].getHandlerFunction());
}
if(allHandlers.indexOf(funcName)>-1)
{
r=true;
}
}
return r;
}

Relink google form to spreadsheet fires onSubmit event for all records

I'm working with google form linked with spreadsheet that has onSubmit trigger. If I unlink form from it's spreadsheet and then link it again with the same spreadsheet google engine creates new sheet and (!) fires onSubmit trigger for all responses that already exist! I discovered it because my onSubmit function creates some spreadsheet based on the answers.
Is it a expected behavior of this mechanism or it just an issue?
P.S.
I've tried to delete onSubmit trigger before create a new link, but it doesn't help:
delete_onsubmit_trigger();
Logger.log('triggers deleted');
//Utilities.sleep(2000); //here I think that perhaps trigger deletion takes some time, but it doesn't help either
set_destination_to_form(form, ss);
set_onsubmit_trigger(ss);
functinons codes are:
function delete_onsubmit_trigger() {
delete_trigger('onSubmit');
}
function delete_trigger(name) {
var triggers, handler;
triggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < triggers.length; i++) {
handler = triggers[i].getHandlerFunction();
if (handler == name) ScriptApp.deleteTrigger(triggers[i]);
}
}
function set_destination_to_form(form, ss) {
form.setDestination(FormApp.DestinationType.SPREADSHEET, ss.getId());
}
function set_onsubmit_trigger(ss) {
ScriptApp.newTrigger("onSubmit")
.forSpreadsheet(ss)
.onFormSubmit()
.create();
}
Any ideas how to bypass this suddenness?