I want to put the time stamp every time someone changes anything on a sheet.
This is a standalone code linked to a file via Sheet ID, it works but only when I run the code.
When I edit the sheet, it doesn't automatically update the time.
Any advice?
function onEdit() {
var s = SpreadsheetApp.openById("1Dshq_jln79nDXMVv8O8_BNcpKMf3TrO08aSNQg-abcM"); // bound the file by Sheet ID then open the specific sheet by name
var ss = s.getSheetByName("H2 OKRs");
var r = ss.getRange("A1:Y100").activate(); // Check the range of entry
if (r) { //checks the column
var nextCell = r.offset(0, 1);
if( nextCell.getValue() === '' ) //is empty?
var date = new Date();
date = Utilities.formatDate(new Date(), "GMT+7", "dd/MM/yyyy HH:mm");
nextCell.getCell(1,1).setValue(date);
};
}
UPDATE: Apparently onEdit() doesnt work well as a standalone script so I embedded it back to Gsheet. Thanks for the help!!
See restrictions, onEdit() simple trigger runs only when the script is attached to a document and cannot be used in a standalone script. You must have the script embeded into the spreadsheet or be an addon in order for it to fire off when you edit the file.
please try with
function onEdit(e) {
...
}
Related
I found this script:
function onEdit () {
var s = SpreadsheetApp.getActiveSheet ();
if (s.getName () == "sheet_name") {
var r = s.getActiveCell ();
if (r.getColumn () == 1) {
var nextCell = r.offset (0, 1);
if (nextCell.getValue () === '')
nextCell.setValue (new Date());
}
}
}
It works if I fill one cell by myself and puts current date to another cell in the right.
BUT if I use Zapier to export my data from Todoist to Google Sheets this script doesn't work. It only works if I change something manually.
Is there any way to make a script which will fill a cell I need with a today date when Zapier export data and fills cells automatically?
Suggestion:
As what Tanaike mentioned, you need to rename your function to something else aside from onEdit() since onEdit is a reserved function name for App Script and use onChange trigger.
But based on how Zapier works, the reason why the current code you have provided is not working is because exports from Zapier is not detected as an active cell, so we would need to revamp the entire code.
Try this instead:
function onZapierUpdate() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet2'); //my test sheet is Sheet2
var range = sheet.getRange(2,1,sheet.getLastRow()-1, 2);
var data = range.getValues();
data.forEach(x => x[0] != "" ? x[1] = new Date() : x);
range.setValues(data);
}
After saving the script, set this on an onChange trigger like so:
Now whenever Zapier exports the data, it changes the content of the spreadsheet which means onChange trigger will take effect.
Reference:
https://developers.google.com/apps-script/reference/script/spreadsheet-trigger-builder#onChange()
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.
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
I'm using Cognito forms to collect information and then using Zapier to pass this information to my google spreadsheet database. I have found that my scripts in google spreadsheets do not trigger the way I would expect.
This one:
function onEdit(event){
var ColCR = 96; // Column Number of "CR"
var changedRange = event.source.getActiveRange();
if (changedRange.getColumn() == ColCR) {
var state = changedRange.getValue();
var adjacent = event.source.getActiveSheet().getRange(changedRange.getRow(),ColCR+1);
var adjacentv = adjacent.getValue();
var timestamp = Utilities.formatDate(new Date(), "GMT-7", "M/dd/yy', 'h:mm a");
switch (adjacentv) {
case "":
adjacent.setValue("("+timestamp+")"+" "+state);
changedRange.clearContent();
break;
default:
adjacent.setValue(adjacentv+"\n"+"("+timestamp+")"+" "+state);
changedRange.clearContent();
break;
}
}
}
Works fine when a user edits the spreadsheet cell directly but not when Zapier updates the cell. It also works on several different types of triggers when the spreadsheet is modified by a user. What is the difference between editing the spreadsheet directly vs having an app like Zapier edit the form? Can I write a script that would see an edit by an app like Zapier?
This one:
function Timestamp() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var cell = sheet.getActiveCell();
var comments = cell.getComment();
var formattedDate = Utilities.formatDate(new Date(), "GMT-7", "M/dd/yy', 'h:mm a ");
Newline works in msgBox, but not in Note.
comments = comments + "Mod: " + formattedDate;
Browser.msgBox(comments);
cell.setComment(comments);
}
Works fine when a user edits a cell and is triggered by a On Change trigger and also works when Zapier updates a cell but when Zapier updates more then one cell in a row it only puts the comment in the first cell in the range. How would I modify the script so that it triggers on every change to every cell and not just the range?
Im sure it has something to do with how Zapier is interacting with my spreadsheet but I don't understand how Zapier edits are any different than user edits?
Thanks for any suggestions or recommendations.
I've experienced this issue as well, and in the end came to the conclusion that the Zapier action uses the API to update the Google Sheet, thus not triggering the trigger. Details available here in Google's documentation of Simple Triggers:
https://developers.google.com/apps-script/guides/triggers/
Situation:
I have a spreadsheet with 20 sheet.
I have other script that copy sheets from other spreadsheet every days to this spreadsheet-
I need to delete every days some specific sheet from a particular spreadsheet.
Problem:
When the script ends to clear the sheets, the spreadsheet hangs and I have to exit and re-enter to the spreadsheet.
I'll appreciate if anyone can help to tunning this script to work without hangging the spreadsheet.
Script:
function shellDeleteSheets(){
var sheets = ['Sheet1','Sheet2','Sheet3','Sheet4','Sheet5'];
for (var s in sheets){
deleteSheetName(sheets[s]);
}
}
function deleteSheetName(stname) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName(stname);
if(!sh) {
return;
}
ss.setActiveSheet(sh);
ss.deleteActiveSheet();
Utilities.sleep(400);
SpreadsheetApp.flush();
}
Try this version I use without issue
function DeleteSheets(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ['sheet1','sheet2','sheet3'];
var numberOfSheets = ss.getSheets().length;
for(var s = numberOfSheets-1; s>0 ; s--){ // in my case I never delete the first sheet
SpreadsheetApp.setActiveSheet(ss.getSheets()[s]);
var shName = SpreadsheetApp.getActiveSheet().getName();
if(sheets.indexOf(shName)>-1){
var delSheet = ss.deleteActiveSheet();
Utilities.sleep(500);
}
}
SpreadsheetApp.setActiveSheet(ss.getSheets()[0]);// send me back to first sheet
}
You could of course use the array of names as an argument for the function or - that's what I do in some cases - give the names of the sheet I need to keep, in this case the if condition is just different .
the sleep can be 400 mS, not sure it makes any difference, I use 500 because at some time I found it more reliable... and I (try to) never change a working solution ;-)
EDIT following your comment :
to make active the sheet called 'Updated' just change the last line of the code like this :
SpreadsheetApp.setActiveSheet(ss.getSheetByName('Updated'));
please note also that I moved this line in the original code, outside of the loop, sorry for this small error ^^