Trigger Google DocumentApp Script Upon Edit of SpreadsheetApp - google-apps-script

Using Google Apps Script, is there a way to have a Google Documents file update automatically whenever a Google Sheets file is edited?
I've got a Google DocumentApp file with a script that gets data from a Google SpreadsheetApp file. I'm looking to create a script to automatically update the DocumentApp file whenever the SpreadsheetApp file is edited.
This is the code I'm using currently:
function updateDocumentOnEditTrigger() {
var ss = SpreadsheetApp.openById(SheetID);
ScriptApp.newTrigger('UpdateDocument')
.forSpreadsheet(ss)
.onEdit()
.create();
}
Running the updateDocumentOnEditTrigger function doesn't seem to trigger the UpdateDocument function, which works as it should when manually run.

Answer:
In order to run a DocumentApp script on edit of a Spreadsheet, the On edit installable trigger attached to the Spreadsheet must be used.
More Information:
As per the Simple Triggers documentation, there are some restrictions which need to be taken into account. In particular:
They can modify the file they are bound to, but cannot access other files because that would require authorization.
As a result, the onEdit(e) trigger function can not be used. There is however an installable trigger which can be created, with settings set up such that it can fire on edit.
Code:
With the following function in the script bound to the Spreadsheet file:
function updateDocument() {
var doc = DocumentApp.openById('DOCUMENT_ID');
// here you can put your code that edits the document in the way you want.
}
You can create an installable trigger which runs on the edit of the Spreadsheet. You will need to run the code at least once before setting up the trigger however - this is because DocumentApp needs authorisation and you need to grant it!
###Setting up an Installable Trigger:
With the code set up, you can create the installable trigger by completing the following steps:
From the Apps Script editor view for the bound Spreadsheet script, follow the path Edit > Current project's triggers. This will open the triggers for the project in a new tab or window.
In the bottom left, click on the + Add Trigger button, bringing up the Add Trigger modal. From here, set up the trigger with the following properties:
Choose which function to run: updateDocument
Choose which deployment should run: Head
Select event source: From spreadsheet
Select event type: On edit
And click Save. This will set up the trigger such that your Document editing function will run each time the Spreadsheet is edited.
References:
Google Apps Script - Simple Triggers
Simple Triggers - Restrictions
Google Apps Script - Installable Triggers

Related

Why Apps Script execution failed only when it is triggered by onEdit event on Google Spreadsheet?

I am working on Google Apps Script. I have apps script that I have wrote that is supposed to be executed by onEdit event on specific sheet.
onEdit.gs
function onEdit(e) {
var syokuninIchiran = new SyokuninIchiran();
syokuninIchiran.syncTable();
}
When the above is executed by edit on the sheet, this error occurs:
You do not have permission to call openById. Required privilege: https://www.googleapis.com/auth/spreadsheets
But, it works with no problem when the script is triggered from Google Apps Script development window. I call the same code by making a test function as follows:
function test(){
var syokuninIchiran = new SyokuninIchiran();
syokuninIchiran.syncTable();
}
It might be problem for this issue? The spreadsheet's owner is not mine. My account has right to edit as the image below.
Try1:
I tried to add the scope manually into the manifest file(appsscript.json). And I approved the authorization. But, nothing changed. It still have the same error message.
{
"oauthScopes": [
"https://www.googleapis.com/auth/sqlservice",
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/script.external_request"
]
}
Answer:
Simple Triggers can not open files aside from the file it is bound to. For this, you need to use an installable trigger.
More Information:
As per the documentation on Simple Trigger restrictions:
Because simple triggers fire automatically, without asking the user for authorization, they are subject to several restrictions:
They can modify the file they are bound to, but cannot access other files because that would require authorization.
So an installable trigger must be used.
Setting up the Installable Trigger:
Follow the Edit > Current project's triggers menu item, which will open a new page in the G Suite Developer Hub. Click the + Add Trigger button in the bottom right and set up the trigger settings as follows:
Choose which function to run: onEdit
Choose which deployment should run: Head
Select event source: From Spreadsheet
Select type of time based trigger: On Edit
And press save. This will increase the range of functionality of your edit triggers.
References:
Simple Triggers | Apps Script | Google Developers
Installable Triggers | Apps Script | Google Developers

How to copy a Google sheet and keep it's project triggers and scripts?

I currently have a Google Sheet that I'm using as a master template. That is, I'm making a copy of this template for every request. I want to add a Google App Script (which onEdit POSTs to my server when the sheeting is completed) to my master template that will be duplicated and run for every copy of this template.
I've tried doing this from an admin account, however, the scripts don't seem to 'stick' with any of the templates. Is this possible?
Installable triggers can be attached to any spreadsheet (respecting sharing permissions) from any project. You can add a new trigger to your master sheets project for each copy that is made. In the second example here they suggest using SpreadsheetApp.openById() you could also use SpreadsheetApp.openByURL() or the Spreadsheet returned by Spreadsheet#copy() depending on how you are duplicating your spreadsheet.
Personally, what I do in 2022 is including something like this on the beginning:
function scriptSetup() {
createOnEditFunction();
}
function createOnEditFunction() {
const ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger('onEdit')
.forSpreadsheet(ss)
.onOpen()
.create();
}
function onEdit(e) {
//your stuff here
}
This way, the scriptSetup() is located on the first line so when copying a spreadsheet I would ask them within Sheets to click on Extensions > Apps Script > Run.
As per Jared Pinkham's link referencing Developer documentation, there are a few things Apps Script can use as triggers other than onEdit.
There are several installable triggers for Google Workspace
applications:
An installable open trigger runs when a user opens a spreadsheet,
document, or form that they have permission to edit.
An installable edit trigger runs when a user modifies a value in a
spreadsheet.
An installable change trigger runs when a user modifies the structure
of a spreadsheet itself—for example, by adding a new sheet or removing
a column.
An installable form submit trigger runs when a user responds to a
form. There are two versions of the form-submit trigger, one for
Google Forms itself and one for Sheets if the form submits to a
spreadsheet.
An installable calendar event trigger runs when a user's calendar
events are updated—created, edited, or deleted.
You can refer to the following link for spreadsheet triggers.

clearContent does not run onChange in Google Sheets script

I have written a script to clear a range of cells (B4:B8) when a specified cell (C1) is changed. However, the cells are not cleared when I edit the specified cell. Here is the script:
function onChange() {
var sheet = SpreadsheetApp.getActive().getSheetByName('Quality Control').getRange('C1');
ScriptApp.newTrigger("clearRange")
.forSpreadsheet(sheet)
.onChange()
.create();
}
function clearRange() {
var sheet = SpreadsheetApp.getActive().getSheetByName('Quality Control');
sheet.getRange('B4:B8').clearContent();
}
The function onChange is set to run onOpen (trigger).
Any idea why this script isn't working?
Short answer
Instead of creating a trigger by code create it manually. Set your trigger to call the clearRange() directly.
Explanation
The script in the question is not working because there is a bug but rather than fixing the bug could be better to set a trigger manually otherwise a new trigger will be created every time that the spreadsheet be opened.
To create a trigger manually, follow the instructions from https://developers.google.com/apps-script/guides/triggers/installable#managing_triggers_manually
Managing triggers manually
To manually create an installable trigger through a dialog in the
script editor, follow these steps:
From the script editor, choose Resources > 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 will be contacted by email if your triggered function fails.
Click Save.
Comments about the code on the question
.forSpreadsheet(sheet) requires that sheet be a spreadsheet object but your code assigns a range to the sheet variable.
From https://developers.google.com/apps-script/reference/script/spreadsheet-trigger-builder#onchange
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("myFunction")
.forSpreadsheet(sheet)
.onChange()
.create();
See https://developers.google.com/apps-script/troubleshooting to learn how to use the debugging tools on the Google Apps Script Editor

Can a standalone script create a trigger for another script which is bound to a spreadsheet?

I am trying to create an installable onEdit trigger for a spreadsheet bound script. I would like to do this programmatically with a separate, standalone script. It looks like this should be possible according to documentation:
Note that, unlike for a simple onOpen() trigger, the script for the installable trigger does not need to be bound to the spreadsheet. To create this trigger from a standalone script, simply replace SpreadsheetApp.getActive() with a call to SpreadsheetApp.openById(id).
https://developers.google.com/apps-script/guides/triggers/installable#managing_triggers_programmatically
However, when I run the code below, the trigger is added to the standalone script project instead of the target, spreadsheet-bound script.
function createSpreadsheetEditTrigger() {
var ss = SpreadsheetApp.openById('1vcAgQ6vPZiILFX0fB_jojyrSdGKr7goD_iCQcFsImEM');
ScriptApp.newTrigger('update')
.forSpreadsheet(ss)
.onEdit()
.create();
}
What am I missing?
Well, this may be possible, but not like that. I think you misunderstood the documentation a bit. Putting in other words, what it says is: to create a installable trigger, a script does not need to be bounded to the target spreadsheet. But the trigger is for the running script itself, as always. There's no installing a trigger for another script.
Scripts can only set triggers for themselves, and there's no API to set a trigger for another script.
You could have the bounded script published as a web-app, then the remote standalone script could call its URL, basically "telling" the bounded script that it's time to set its installable trigger.

Installable onEdit trigger in google spreadsheet script when copying a template spreadsheet script

I have a script(A) that copies a template spreadsheet. This template spreadsheet has a script(B) in it. The template spreadsheet and script are successfully programmatically copied and shared with others. The template script needs to use an onEdit() trigger to modify a third spreadsheet (Edits in the copy of the template spreadsheet are going to be synced to the third spreadsheet). A simple trigger does not have permission to access the third spreadsheet. I have tried using installable triggers, but have had no success in getting an installable onEdit trigger to work in the copied spreadsheet.
What I want to achieve is to have an onEdit trigger in the copied spreadsheet that does not require separate authorization to write to a third spreadsheet.
All spreadsheets are owned by a single user.
I can create an installable trigger in script B using the following code in script A.
createSpreadsheetEditTrigger(id_of_shared_spreadsheet)
...
...
function createSpreadsheetEditTrigger(idss) {
var ss = SpreadsheetApp.openById(idss);
ScriptApp.newTrigger('myOnEdit')
.forSpreadsheet(ss)
.onEdit()
.create();
}
The 'myOnEdit' function is in script B and has in it the code that syncs to the third spreadsheet. This is not triggered when the copied spreadsheet is edited.
If I create the installable trigger in script B by calling it from a simple onOpen() function it fails because of permissions.
Following the advice here: Execution failed: You do not have permission to call getProjectTriggers I can create the installable trigger and a menu item to call it, plus a msgbox that prompts the user to click on install and authorize the trigger.
Is it possible to programmatically install an onEdit trigger when copying spreadsheets that has permissions to edit a third spreadsheet without the user having to manually authorize the trigger?
Many thanks in advance
Trevor Storr
I just went through this same sort of deal, I am pretty confident there is not an "easy" way to make this happen without Authorization.
Although you can assign your "createSpreadsheetEditTrigger" script to a button that just installs the trigger and authorizes all at the same time, 3 clicks and 5 seconds, then it will work just as you intended.