How to allow function in protected Google Sheets? - google-apps-script

I am using below code to get the last update date in Column B. Now when I protect the column B (because I don't want the other users to make any changes) and share this sheet with other users the update is not happening.
I would appreciate your help.
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetName = "Sheet1";
var s = SpreadsheetApp.getActiveSheet();
if (s.getName() !== sheetName) return;
var r = s.getActiveCell();
if( r.getColumn() != 2 ) { //checks the column
var row = r.getRow();
var time = new Date();
time = Utilities.formatDate(time, "GMT+5", "dd/MM/yy, hh:mm:ss");
SpreadsheetApp.getActiveSheet().getRange('B' + row.toString()).setValue(time);
};
};

Instead of using an simple trigger use an installable trigger.
The above is because simple triggers are only able to execute tasks that don't require authorization.

Related

Insert Timestamp when copy/paste whole row and value inserts/edits in Column C in google sheets

I tried inserting timestamp when a row is being copied and data inserts or edits in Column C same row cell, but it works only on manual entry, not on copy-paste.
Please suggest to me what I am missing or doing wrong.
function onChange() {
var s = SpreadsheetApp.getActiveSheet();
var sName = s.getName();
var r = s.getActiveCell();
var row = r.getRow();
var ar = s.getActiveRange();
var arRows = ar.getNumRows()
// Logger.log("DEBUG: the active range = "+ar.getA1Notation()+", the number of rows = "+ar.getNumRows());
if( r.getColumn() == 3 && sName == 'Sheet1') { //which column to watch on which sheet
// loop through the number of rows
for (var i = 0;i<arRows;i++){
var rowstamp = row+i;
SpreadsheetApp.getActiveSheet().getRange('F' + rowstamp.toString()).setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm"); //which column to put timestamp in
}
}
}//setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm:ss");
Use getLastColumn() to check whether column C is included in the pasted range.
Use getNumRows() to get the number of rows your copied range has, and so add the timestamp to all these rows.
No need to used an installed onChange() for this, a simple onEdit() is enough.
I'd also suggest to use event object in order to get information on which range was edited (even though this way you won't be able to fire this successfully from the script editor).
Edit: if you want to remove the timestamp when the range is cleared, you can just check that's the case, using every, or some, and clearContent if that's the case.
Code snippet:
function onEdit(e) {
var s = SpreadsheetApp.getActiveSheet();
var r = e.range;
var firstRow = r.getRow();
var numRows = r.getNumRows();
var firstCol = r.getColumn();
var lastCol = r.getLastColumn();
if((firstCol <= 3 || lastCol >= 3) && s.getName() == 'Sheet1') {
var emptyRange = r.getValues().every(row => row.every(value => value === ""));
var destRange = s.getRange(firstRow, 6, numRows);
if (emptyRange) destRange.clearContent();
else {
var dates = new Array(numRows).fill([new Date()]);
destRange.setValues(dates).setNumberFormat("MM/dd/yyyy hh:mm");
}
}
}
The following script will create timestamps starting from column F until the last column when you copy the row.
I think you are looking for this:
function onEdit(e) {
const startCol = 6; // column F
const s = e.source.getActiveSheet();
const sName = s.getName();
const ar = e.range;
const row = ar.getRow();
const arColumns = ar.getNumColumns();
const arRows = ar.getNumRows();;
if( sName == 'Sheet1') {
const rng = s.getRange(row,1,arRows,s.getMaxColumns());
check = rng.getValues().flat().every(v=>v=='');
if(check){
rng.clearContent();
}
else{
s.getRange(row,startCol,arRows,s.getMaxColumns()-startCol+1).setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm");
}
}
}
Note:
Again, onEdit is a trigger function. You are not supposed to execute it manually and if you do so you will actually get errors (because of the use of the event object). All you have to do is to save this code snippet to the script editor and then it will be triggered automatically upon edits.

onedit script in google sheet works for only one function

I have 2 scripts in the same project but it seems that only one is working, not specific but depending on the time I add the script, it is like the last script Im adding disabling the other.
these are the 2 scripts (I copied from google forum and updated according to my needs):
adding an auto time stamp to a cell when specified range is not empty:
function onEdit(event) {
var sp = SpreadsheetApp.getActiveSheet();
var c = sp.getActiveCell();
if (c.getColumn() < 9 && sp.getName()=='QUE') {
var celladdresp ='I'+ c.getRowIndex()
sp.getRange(celladdresp).setValue(new Date()).setNumberFormat("dd/mm/yy hh:mm");
}
};
copy a row to another sheet on the same file if checkbox is checked (=true):
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "QUE" && r.getColumn() == 12 && r.getValue() == true) { var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("QUE2");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns-2).copyTo(target);
}
};
Your help understanding why they dont work together will be appreciated.
*BTW I tried to Enable/Disable new apps scriptspowered by chrome v8 but did not helped
Answer:
You can only have one onEdit(event) function per script. If you wish both functions to run on edit, you need to combine them.
More Information
It's programming 101 that all functions and variables have to have unique names - otherwise your code isn't going to know which function or variable you're referring to. The uniqueness is important as you're defining exactly what you want.
In this case, as you have two onEdit(event) functions, when the sheet is edited your script is only calling one of these functions. This makes sense - it has no reason to continue looking for more doGet()s if it's already found and executed one.
Merging Functions:
When merging, it's important not to replicate code that is unneccesary. Reducing the number of calls so you only do exactly what you need to is important for efficient-running code:
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet()
var r = event.source.getActiveRange();
var c = sheet.getActiveCell();
if (c.getColumn() < 9 && sheet.getName() == 'QUE') {
var celladdresp = 'I' + c.getRowIndex()
sheet.getRange(celladdresp).setValue(new Date()).setNumberFormat("dd/mm/yy hh:mm");
}
if(sheet.getName() == "QUE" && r.getColumn() == 12 && r.getValue() == true) { var row = r.getRow();
var numColumns = sheet.getLastColumn();
var targetSheet = ss.getSheetByName("QUE2");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(row, 1, 1, numColumns-2).copyTo(target);
}
}

Only use script in one sheet

I use this script to set a timestamp when a cell is changed. But it triggers in all sheets, and I only want it to be triggered when I do a change in sheet "XXX"
function onEditDatoMaxboStart() {
var s = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("XXX"); //change this to the name of your sheet
var r = s.getActiveCell();
if( r.getColumn() != 29 ) {
var row = r.getRow();
var time = new Date();
time = Utilities.formatDate(time, "GMT+01:00", "dd.MM.yyyy hh.mm.ss");
SpreadsheetApp.getActiveSheet().getRange('AP' + row.toString()).setValue(time);
};
};
How do I lock it to only be triggered when I make a change in the sheet "XXX"?
You cannot lock onEdit triggers to be ran on specific Sheets. However, within your onEdit function, you can check whether the Sheet that has triggered the action is the one you are targeting. If it is not, you can just return from the function without really executing any action. Your modified function would look as follows (edited only the first two lines):
function onEditDatoMaxboStart(e) {
if (e.range.getSheet().getName() !== "XXX") return;
var s = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("XXX"); //change this to the name of your sheet
var r = s.getActiveCell();
if( r.getColumn() != 29 ) {
var row = r.getRow();
var time = new Date();
time = Utilities.formatDate(time, "GMT+01:00", "dd.MM.yyyy hh.mm.ss");
SpreadsheetApp.getActiveSheet().getRange('AP' + row.toString()).setValue(time);
};
};
Also, I suggest you check out this page on using events objects obtained in trigger functions.

function onEdit() runs only partially

I have a very frustrating problem on my hands and I turn to you for help once more. I had the onEdit() function below which, together with the auxiliary functions, worked fine.
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activeSheet = ss.getActiveSheet();
var activeCell = activeSheet.getActiveCell();
//Check if the sheet is a JOb sheet and the cell us the status cell
if ( activeSheet.getName().indexOf("Job ID") != -1 && activeCell.getRow() == 4 && activeCell.getColumn() == 15 ) {
var targetSheet = ss.getSheetByName('Active Jobs');
var jobRowNumber = findJobIdRow();
var sourceCell = activeSheet.getRange(4,15);
sourceCell.copyTo(targetSheet.getRange(jobRowNumber,16));
}
if (activeSheet.getName().indexOf("Job ID") != -1 && activeCell.getRow() == 2 && activeCell.getColumn() == 15){
var switchValue = activeCell.getValue();
switch (switchValue){
case "On hold (i)":
case "On hold (ii)":
case "On hold (iii)":
case "To be assigned":
//Write date to active jobs sheet
addDateToActive("TBC");
break;
case "In progress":
var newDate = Browser.inputBox("Please enter report out date, example 18-Aug-2017");
addDateToActive(newDate);
break;
//default:
//Browser.msgBox("GOTHERE");
}
}
}
function findJobIdRow() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var jobID = ss.getActiveSheet().getRange(2,1).getValue();
var column = ss.getSheetByName('Active Jobs').getRange(2,1,ss.getSheetByName('Active Jobs').getMaxRows()-2,1);
var values = column.getValues(); // get all data in one call
for(var ct = 0; ct < values.length-1; ct++){
if(values[ct][0] == jobID){
var ct = ct+2;
break;
}
}
return ct;
}
function addDateToActive(input){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activeSheet = ss.getActiveSheet();
var activeCell = activeSheet.getActiveCell();
var jobid = activeSheet.getRange(2,1).getValue().toString();
var activeJobSheet = ss.getSheetByName("Active Jobs");
var activeJobs = activeJobSheet.getRange(1,1,activeJobSheet.getLastRow(),1).getValues();
activeJobs = ColumnToArray(activeJobs);
var jobrow = activeJobs.indexOf(jobid)+1;
if (jobrow == -1){
Browser.msgBox("Job Id not preent on Active Jobs sheet");
}else{
activeJobSheet.getRange(jobrow,15).setValue(input);
}
}
Then I included some code in this script which was supposed to send out some e-mails to people if some dates were approaching today's date. There were some problems with that code because of authorization requirement so I moved it into it's own separate function and came back to the original script that is posted above. Now the problem I am facing is, although this script works fine if ran from the script editor, manually run from a drawing button in the spreadsheet, or is ran by a on edit trigger I set up from the "Current project triggers" menu, it will not do the entire script if the script is triggered by the onEdit() function name. It does the first bit where it copies the content of a cell across but not the second bit with the case switch.
The obvious fix would be to just set up the trigger from the "Current project triggers" but this onEdit detection needs to apply to anyone in my team that edits this sheet. If I set it up like that it will work for me but no one else from my team.
Any help would be appreciated.
Setting up the trigger via the function name onEdit() proving tricky I wrote this bit of code and attached it to a drawing in the sheet. Then instructed all the users to click it which set up the trigger for them. This solved the problem and the trigger works fine now.
function triggerSetUp(){
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("enforcer").forSpreadsheet(sheet).onEdit().create();
}

Apps Script set ActiveUser and timestamp

Please help with setting active user in Column N. This script will timestamp column M whenever a cell in a row is updated. However, nothing updates in Column N for the active user.
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
if( s.getName() == "Log" ) { //checks that we're on the correct
sheet
var r = s.getActiveCell();
var user = Session.getActiveUser().getEmail();
if( r.getColumn() != 13 ) { //checks the column
var row = r.getRow();
var time = new Date();
time = Utilities.formatDate(time, "GMT-07:00", "yyyy-MM-dd, hh:mm:ss");
SpreadsheetApp.getActiveSheet().getRange('M' + row.toString()).setValue(time);
SpreadsheetApp.getActiveSheet().getRange("N" + row.toString()).setValue(user);
}
};
};
Am I using setValue(user) incorrectly?
Your call to setValue() looks fine. You may be encountering an authorization issue.
Can you successfully run this same code outside of the onEdit() trigger?
There are restrictions on the actions that can be performed inside of an onEdit trigger. See https://developers.google.com/apps-script/guides/triggers/