How to trigger a google spreadsheet function onEdit? - google-apps-script

function oneWeek() {
var sheetURL = SpreadsheetApp.getActive().getUrl()
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(spreadsheet.getSheets()[0]);
var sheet = spreadsheet.getActiveSheet();
// do stuff with sheet
}
How do I get this function to trigger onEdit?
I've tried this for the sheet,
function onEdit(event) {
var sheet = event.source.getSheetByName('x');
// do stuff with sheet
}
EDIT: I forgot to mention that my script did https request so that's the reason onEdit didn't work. The solution is here: https://productforums.google.com/forum/#!topic/docs/0nxLYWXVo6Y
Because this script does other things, like a HTTP request, it cannot be assigned to the default onEdit() functions, you need to create it as a custom function and assign it in the Edit menu. Edit->Current Project Triggers and create a new one for onEdit. Just point it at your function and you’re done.

function onEdit(e){
if(e.range.getSheet().getName()!='x'){return;}
//do stuff on sheet x here
}

Related

Function based trigger using Sheet instead of Spreadsheet failing

I have two form feeding into the same sheet and I need different triggers for each sheet.
Tried to trigger using function based triggers but that is not working.
This function works:
function testTrigger() {
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("myFunction")
.forSpreadsheet(sheet)
.onChange()
.create();
}
This one fails:
function testTriggerTwo() {
var sheet = SpreadsheetApp.openById("...").getSheetByName("Responses");
ScriptApp.newTrigger("myFunction")
.forSpreadsheet(sheet)
.onChange()
.create();
}
with
"Exception: The parameters (SpreadsheetApp.Sheet) don't match the method signature for ScriptApp.TriggerBuilder.forSpreadsheet."
Any ideas?
function testTrigger() {
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("myFunction")
.forSpreadsheet(sheet)//this sheet is a class Spreadsheet
.create();
}
This one fails:
function testTriggerTwo() {
var sheet = SpreadsheetApp.openById("...").getSheetByName("Responses");
ScriptApp.newTrigger("myFunction")
.forSpreadsheet(sheet)//this sheet is a class Sheet
.onChange()
.create();
}
One of the problems in dealing with Google Apps Script and Google in general is that the people that sell products decided to begin to use the term Sheet as being synonymous with Spreadsheet but in the Apps Documentation Sheet refers to Excel like worksheet and I guess Spreadsheet refers to the excel like workbook. One is the file and the other is a tab. In the second version of the function you are using a Class Sheet when you should be using a Class Spreadsheet.
I would recommend using something like this for trigger creation to avoid the possibility of creating more that one trigger for any given function which can produce issues that are hard to debug.
function testTrigger() {
const ss = SpreadsheetApp.getActive();
if (ScriptApp.getProjectTriggers().filter(t => t.getHandlerFunction() == "myFunction").length == 0) {
ScriptApp.newTrigger("myFunction")
.forSpreadsheet(ss)
.onChange()
.create();
}
}
By checking that none of the project project triggers have a handler with the same function name you can insure that you don't have two triggers for the same function.
You can control it by getting the the sheet name (where the response is landing)
function onFormSubmit(e) {
var sheet = e.range.getSheet().getName();
//do whatever you want by comparing the sheet name
}
You can have only one onFormSubmit Trigger.
But, you can do different things by an if statement

OnFormSubmit() not firing

I am trying to solve the following case: I have a template that is copied by users and linked to a Google Form. Also, I have a script that does some configuration to the Form Responses tab for its further usage. It works perfectly in the template, however, the installable onFormSubmit() trigger is not copied together with the template. To solve this I added onOpen() trigger that installs the onFormSubmit() which was confirmed to work.
The issue I am facing is that while onFormSubmit() is successfully installed in the template copy, it still does not fire automatically. I assume that this is related to some permissions issue. Is there any way to rewrite the script to avoid additional authorization?
function onOpen(e) {
addFormSubmissionListener();
//// other init...
}
function addFormSubmissionListener() {
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("onFormSubmit")
.forSpreadsheet(sheet)
.onFormSubmit()
.create();
}
function onFormSubmit(e) {
var range = e.range
var sheet = range.getSheet();
var spreadsheet = SpreadsheetApp.getActive();
if(spreadsheet.getSheetByName('Responses') == null) {
sheet.setName('Responses');
sheet.insertColumnsAfter (7,10)
spreadsheet.getRange('Tech!A:J').copyTo(spreadsheet.getRange('Responses!H:O'), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
sheet.hideColumns(16, 2)
var curr_sheet = spreadsheet.getSheetByName('Jira import')
updateFormulasTwoRows(curr_sheet);
}
}
Answer:
If you create a new project you will always have to authorise it, there isn't really a way of getting around this.

Google app script - Getting last sheet row updated

I have a script associated with a google sheet that it's call after a Google form is submitted.
Actually I can get all rows or the last but in case one form answer is updated I need to find this row updated to make my treatment.
Is there a way to do that?
This is my two case:
// Getting last row data
function getSpreadSheetLastRowData() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var row = sheet.getLastRow();
return sheet.getRange('A'+row+':BG'+row).getValues();
}
// Getting all rows data
function getSpreadSheetAllData() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var row = sheet.getLastRow();
return sheet.getRange('A2:BG'+row).getValues();
}
You will need to write an event handler for the onFormSubmit event object and attach it to your spreadsheet.
From the Spreadsheet linked to your Form go to Tools > Script Editor.
Here write a function to install the trigger:
function installTriggerToSpreadsheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ScriptApp.newTrigger('sumbissionHandler')
.forSpreadsheet(ss)
.onFormSubmit()
.create();
}
Now your trigger will handle the form submission calling the submissionHandler function inside the Spreadsheet context.
This means you can read the affected row by using a function like this:
function submissionHandler(e) {
var affectedRow = e.range.getRow();
// ... Apply your treatment.
}
References:
Triggers
Event Objects
If you have a script that is triggered by a form submission then take the event object lets call it e. Then e.range is the range that was edited in the linked sheet. So e.range.getRow() is the row and e.range.getSheet().getName() is the name of the linked sheet.
form submit object for spreadsheet

Set trigger in script in Google Sheets programmatically

I am trying to get a Google Apps Script to trigger on edit of a particular cell. Right now I have achieved this using a run-time trigger option built in Google Sheets. However, I lose the run-time trigger when I make a copy.
Hence, I have managed to find a programmable trigger from various sources and patched something together, but it is not working. I have no programming knowledge, so I am unable to understand where I am going wrong.
My objective is to run the script when user edits the Named Range "monthfilter".
With script trigger creation
function HideColumns() {
//open the current spreadsheet and get the value of the named range and trigger project
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger("monthfilter").forSpreadsheet(ss).onedit()
var name = ss.getRangeByName("monthfilter");
var namevalue = name.getValue();
My previous function:
function HideColumns() {
//open the current spreadsheet and get the value of the named range
var ss = SpreadsheetApp.getActive();
var name = ss.getRangeByName("monthfilter");
var namevalue = name.getValue();
//show or hide February
if (namevalue == "February") {
var sheet = ss.getSheetByName("MIS");
sheet.hideColumns(30);
/** other stuff */
Not sure what is the 'runtime trigger' you mean, there are three kinds of trigger:
Simple trigger
Installable trigger
Time driven trigger
onEdit(e) is just a Simple trigger.
Let's take a look to the following situation:
yourMainSpreadsheet - (You are the owner)
|
binding script functions: - 1. function makeCopy( ) {...}
2. function monthFilter(e) {...}
3. function onEdit(e) { monthFilter(e); }
|
| After copying, new spreadsheet remains all functions and simple trigger.
V
newSpreadsheet- (You are the owner, maybe share with other editors.)
|
binding script functions: - 1. function makeCopy() {...}
2. function monthFilter(e) {...}
3. function onEdit(e) { monthFilter(e); }
No matter what kind of trigger you use or just manually run makeCopy() in yourMainSpreadsheet, onEdit(e) would be copied to new spreadsheet too, and it works when you or other editors make edits, you don't need to do anything:
function makeCopy(){
var mainSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var newSpreadsheet = mainSpreadsheet.copy('newSheet');
}
function monthFilter(e) {
var thisSheet = e.source.getActiveSheet();
var name = thisSheet.getRangeByName("rangeMonthfilter");
var nameValue = name.getValue();
//...
}
function onEdit(e) {
monthFilter(e);
}
What you have done is set a installable trigger to new spreadsheet.
Highlight of documentation about difference between them.
Installable triggers, however, offer more flexibility than simple
triggers: they can call services that require authorization ...
For example:
function monthFilter(e) {
var thisSheet = e.source.getActiveSheet();
var name = thisSheet.getRangeByName("rangeMonthfilter");
var nameValue = name.getValue();
// If you have operation like:
var onlyYouHavePermission = SpreadsheetApp.openById('xxxxxxxxx');
/* This is not allowed if you just use Simpler trigger onEdit(e) to
drive monthFilter(). */
}
For this, now is the time to use installable trigger:
function makeCopy(){
var mainSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var newSpreadsheet = mainSpreadsheet.copy('newSheet');
ScriptApp.newTrigger('monthFilter')
.forSpreadsheet(newSpreadsheet)
.onEdit()
.create();
/* The host of this trigger is you, it's like you
deploy a trigger to the newSpreadsheet, and make other editors
available to do something on "onlyYouHavePermission" through it.*/
}
Update
If all you want to do is just in HideColumns() you provide, you just need to add a new function which is a simpler trigger in script editor:
function onEdit(e) {
var ss = SpreadsheetApp.getActive();
var name = ss.getRangeByName("monthfilter");
var namevalue = name.getValue();
if (namevalue == "February") {
/* If you copy the spreadsheet, of course including the sheets
inside it, and you share the permission of the new spreadsheet to
other editors, because they own the permission, authorization
is not required here.
*/
var sheet = ss.getSheetByName("MIS");
sheet.hideColumns(30);
}
}

Trigger when user switches between sheets

Is there a way on to run a script whenever the user switches between sheets in a Google Sheets Spreadsheet?
More or less like onOpen, but instead of running when the document is opened, it should fire every time the user switches to another sheet.
Here is my work-around for onSheetChange:
function saveActiveSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var actsheet = ss.getActiveSheet();
// The onSelectionChange() function executes in a separate thread
// which does not use any script global variables, so use the
// PropertiesService to maintain the user global state.
var userProperties = PropertiesService.getUserProperties();
userProperties.setProperty('ACTIVE_SHEET', actsheet.getSheetName());
}
function onSheetChange(e) {
// Do anything needed after a new sheet/tab selection
}
function onSelectionChange(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
// Get current sheet name and compare to previously saved sheet
var currentactsheet = ss.getActiveSheet();
var currentactsheetname = currentactsheet.getSheetName();
var userProperties = PropertiesService.getUserProperties();
var actsheetname = userProperties.getProperty('ACTIVE_SHEET');
if (currentactsheetname !== actsheetname) { // New sheet selected
saveActiveSheet();
onSheetChange(e); // Call custom sheet change trigger
}
// Do anything needed when a different range is selected on the same sheet
else {
var range = e.range;
}
}
function onOpen(e) {
saveActiveSheet();
}
UPDATE: On April 2020 Google added onSelectionChange(e) which could be used to check if the user switched between sheets aka tabs.
At this time there isn't a trigger related to switch for one sheet to another. To learn about the available triggers in Google Apps Script, please checkout Triggers and events - Google Apps Script Guides
As a workaround you could a custom menu to and SpreadsheetApp.setActivesheet to switch between sheets by using a script instead of using tabs and including in that script a call to the function to be run when switching from one sheet to another.
I have created a "Feature request" to implement "onSheetChange" trigger at google issue tracker. You can star it, so google now you want this:
https://issuetracker.google.com/issues/72140210
And here is related question with possible workaround: How to capture change tab event in Google Spreadsheet?
you can use
sheet1.showSheet();
sheet2.hideSheet();