Set trigger in script in Google Sheets programmatically - google-apps-script

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);
}
}

Related

Creating installable trigger in a spreadsheet using custom library - google app script

I have a stand alone library script that contains functions to create an installable onEdit trigger.
The idea is to use this library in a bound script of a new spreadsheet to create an installable trigger native to the new spreadsheet.
So far I have ensure the library is shared to "Anyone with link can access", I've added the library to the new spreadsheet bound script and it seems to have access to all the library functions.
I can execute the function to create the trigger but the trigger continuously fails with the error "Script function not found: onEditTrigger".
The library code that seems to be causing the issue is contained in the createOnEditTrigger function. Theoretically the createOnEditTrigger function should be called from the bound script once after adding the library:
var onEditTriggerID = ScriptApp.newTrigger("onEditTrigger")
.forSpreadsheet(ssID)
.onEdit()
.create()
.getUniqueId();
The onEditTrigger function that is referred to in the error is also within the same library. It takes in the event parameter and uses the range and value to determine other functions to execute within the same library:
function onEditTrigger(e)
{
var range = e.range;
var value = e.value;
var row = range.getRow();
var col = range.getColumn();
var ssObj = e.source;
var spreadsheetID = ssObj.getId();
// training Plan Ranges that can be edited
var exerciseCheckboxRanges = ["A11","A14","A21", "A24","A28","A31","A35", "A38", "A42"];
var exerciseLoadRanges = ["R10","R13","R20", "R23","R27","R30","R34", "R37", "R41"];
var rateWorkoutRange = "S44";
var trainingPlanSheet = ssObj.getSheetByName("Training Plan");
var trainingPlanData = trainingPlanSheet.getDataRange().getValues();
var workoutCompleteIndex = indexOf2d(trainingPlanData,"Workout Completed");
var workoutCompleteRow = workoutCompleteIndex[0] + 1;
var workoutCompleteRange = "I" + workoutCompleteRow;
if(exerciseCheckboxRanges.includes(range.getA1Notation()))
{
// exercise checkboxes
exerciseCheckboxTrigger(spreadsheetID, value, range);
}
if(exerciseLoadRanges.includes(range.getA1Notation()))
{
exerciseLoadTrigger(spreadsheetID,value, range.getA1Notation());
}
if(range.getA1Notation() == workoutCompleteRange)
{
if(value)
{
var ui = SpreadsheetApp.getUi();
var response = ui.alert('This will move you onto the next session, are you sure you want to continue?', ui.ButtonSet.YES_NO);
// Process the user's response.
if (response == ui.Button.YES)
{
completeWorkoutTrigger(spreadsheetID,value,range.getA1Notation());
}
else
{
return;
}
}
}
}
Can anybody provide any insight into why this is happening?
I should note that I can create the trigger fine and it works exactly as expected if the createOnEditFunction is executed from the original standalone library script and not from using the library in the bound script. However the trigger is created in the original library script and not the bound script which is not ideal.

onEdit specific cell copy data from one google sheets to another

In google sheets, I am trying to get one data to copy from one sheet to another.
I have this code which is working however I would like it to run onEdit when changing cell E4 in Googlesheet1. I am new at this and doesn't seem to get it to quite work with the solutions I found online.
function ExportRange() {
var destination = SpreadsheetApp.openById('googlesheet1');
var destinationSheet = destination.getActiveSheet();
var destinationCell = destinationSheet.getRange("AC3");
var cellData = '=IMPORTRANGE("https://docs.google.com/spreadsheets/googlesheet2", "AE10:AE9697")';
destinationCell.setValue(cellData);
}
Chose between a simple and installable onEdit trigger, depending on your requirements
For most applciaitons a simple onEdit trigger is sufficient, to use it you just need to rename your function ExportRange() to onEdit()
Take advantage of event objetcs that give you informaiton about the event that fired the trigger
So, the trigger onEdit can give you among others information about the event range - that is the range that has been edited
Now you can implement an if statement to specify that the rest of the funciton shall only be run if the event range and the corresponding sheet are as required
Sample:
function onEdit(event) {
var range = event.range;
var sheet = range.getSheet();
if(range.getA1Notation() == "E4" && sheet.getName() == "Googlesheet1"){
var destination = SpreadsheetApp.openById('googlesheet1');
var destinationSheet = destination.getActiveSheet();
var destinationCell = destinationSheet.getRange("AC3");
var cellData = '=IMPORTRANGE("https://docs.google.com/spreadsheets/googlesheet2", "AE10:AE9697")';
destinationCell.setValue(cellData);
}
}
Please note that this function can only be fired by the trigger in
case of an edit. If you try to run it manually, it will give you an
error because event (and thus event.range) will be undefined if
the funciton was not called by an edit event.

Google sheets - User/Email stamp triggered ON EDIT works only with OWNER account - how to enable user/email stamps for all editors?

I need a solution to enable all editors to leave their name stamps after they make changes in a sheet. I was able to come up with script code which does work ONLY FOR OWNER.
I tried to authorize the script by running the script manually from editors accounts - the app has the authorization but even though it doesn't work for Editors.
Norbert Wagner: "However authorizing from the script editor did not work for me. But as soon as I added a menu in the document and executed the function from there, I got an authorization request in the document. From then on also the onEdit function works, for all users. I did this as the documents owner though. " -
maybe this is the solution? But how can I run the onEdit from the
document? Simple edit doesn't work, but how about this menu? Is there
a way to execute ALL SCRIPTS AND FORCE AUTHORIZATION from document level?
function onEdit(e) {
// Your sheet params
var sheetName = "Arkusz1";
var dateModifiedColumnIndex = 3;
var dateModifiedColumnLetter = 'C';
var range = e.range; // range just edited
var sheet = range.getSheet();
if (sheet.getName() !== sheetName) {
return;
}
// If the column isn't our modified date column
if (range.getColumn() != dateModifiedColumnIndex) {
var row = range.getRow();
var user = Session.getActiveUser().getEmail();
user = String(user);
user = user.replace('#gmail.com', '');
var dateModifiedRange = sheet.getRange(dateModifiedColumnLetter + row.toString());
dateModifiedRange.setValue(user);
};
};
This function works only when using owner account.
Even after Editor has authorised script manually from script editor - the onEdit user stamp function doesn't trigger.
Below is another function which I used for testing. When I run it manually from editors account IT WORKS - it saves editor's name in A1.
function USERNAME(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0]; // this will assign the first sheet
var cell = sheet.getRange('A1');
var d = new Date();
d.setHours(d.getHours() +1);
var user = Session.getActiveUser().getEmail();
user = String(user);
user = user.replace('#gmail.com', '');
cell.setValue(user);
}
In fact you have to use installable trigger.
Rename your function onEdit(e) with another name for example customFunction(e)
Then you setup an installable trigger using this function :
function createTrigger(){
ScriptApp.newTrigger('customFunction')
.forSpreadsheet(SpreadsheetApp.openById('YOU_SHEET_ID'))
.onEdit()
.create();
}
Or you can setup the trigger manually by going to 'Edit >> Current project's triggers >> Click on + button (bottom right)'
By this way trigger will run each time there is an Edit no matter the user.
Stéphane

How to trigger a google spreadsheet function onEdit?

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
}

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();