How to create timestamp on multiple columns in GSheet - google-apps-script

Am havong some trouble creating a script to automate timestamp on GSheet. I have 2 columns - AD & AE, that I want it to have the date timestamp for when column L and AA are updated. Have tried the following script but doesn't seem to work.
function onEdit(e) {
addTimestamp(e);
}
function addTimestamp(e){
var startRow = 3;
var targetColumn = 12;
var targetColumn2 = 27;
var ws = "Brand List";
var row = e.range.getRow();
var col = e.range.getColumn();
if (col === targetColumn && row >= startRow && e.source.getActiveSheet().getName() === ws) {
var currentDate = new Date();
e.source.getActiveSheet().getRange(row,30).setValue(currentDate)
}
if (col === targetColumn2 && row >= startRow && e.source.getActiveSheet().getName() === ws) {
var currentDate = new Date();
e.source.getActiveSheet().getRange(row,31).setValue(currentDate)
}
}

Your script is working fine, but it seems that you're getting an error saying TypeError: Cannot read property 'range' of undefined.
This happens because the script is using a trigger to execute the function onEdit() whenever the spreadsheet is edited.
When executed, this trigger will pass an event object (e) as an argument to the function, which includes data such as the cell that was edited.
However, this event object is only passed if the sheet is edited, which doesn't happen if you run the function from the script editor.
So, to make it work, you need to edit the sheet as you'd do when using the script.
If you actually want to test it separately, you'd need to explicitly create this event object and pass it to the onEdit() function: How can I test a trigger function in GAS?

For those interested in the script used.
function onEdit(e) {
addTimestamp(e);
addTimestamp2(e);
}
function addTimestamp(e){
var startRow = 3;
var targetColumn = 12;
var targetColumn2 = 27;
var ws = "Brand List";
var row = e.range.getRow();
var col = e.range.getColumn();
if (col === targetColumn && row >= startRow && e.source.getActiveSheet().getName() === ws) {
var currentDate = new Date();
e.source.getActiveSheet().getRange(row,30).setValue(currentDate)
}
}
function addTimestamp2(e){
var startRow = 3;
var targetColumn = 12;
var targetColumn2 = 27;
var ws = "Brand List";
var row = e.range.getRow();
var col = e.range.getColumn();
if (col === targetColumn2 && row >= startRow && e.source.getActiveSheet().getName() === ws) {
var currentDate = new Date();
e.source.getActiveSheet().getRange(row,31).setValue(currentDate)
}
}

Related

Use range instead of array of indivdual cells

I have this code which works for cells A2-A4:
//The function onEdit ensures that checkboxes deleted (by mistake) in the sheet are immediately re-created.
function onEdit(e) {
var spreadsheet = SpreadsheetApp.getActive();
if(spreadsheet.getSheetName()=='MySheet') { //to avoid executing for another sheet
var checkboxCells = [
'A2','A3','A4'];
var range = e.range;
var value = range.getValue();
var a1Notation = range.getA1Notation();
if (checkboxCells.indexOf(a1Notation) != -1 && value != 'TRUE' && value != 'FALSE') {
range.insertCheckboxes();
}
}
};
However I need to work with a 1D range (since there are many cells) and hence I am trying to use this:
//The function onEdit ensures that checkboxes deleted (by mistake) in the sheet are immediately re-created.
function onEdit(e) {
var spreadsheet = SpreadsheetApp.getActive();
if(spreadsheet.getSheetName()=='MySheet') { //to avoid executing for another sheet
var checkboxCells = spreadsheet.getSheetByName('MySheet')
.getRange('MyRange').getA1Notation();
var range = e.range;
var value = range.getValue();
var a1Notation = range.getA1Notation();
if (checkboxCells.indexOf(a1Notation) != -1 && value != 'TRUE' && value != 'FALSE') {
range.insertCheckboxes();
}
}
};
I think this second version should work, but it does not.
Why does it not work?
Modification points:
In order to check whether the edited cell is included in the specific range you expect, the following sample script can be used. (var { range } = e;)
var checkboxCells = sheet.getRange('MyRange');
var startRow = checkboxCells.getRow();
var endRow = startRow + checkboxCells.getNumRows() - 1;
var startCol = checkboxCells.getColumn();
var endCol = startCol + checkboxCells.getNumColumns() - 1;
var check = range.rowStart >= startRow && range.rowEnd <= endRow && range.columnStart >= startCol && range.columnEnd <= endCol;
In order to check whether the edited cell is the checkbox, isChecked() can be used. In this case, when the cell is the checkbox, true or false are returned. When the cell is not the checkbox, null is returned. I thought that this might be able to be used.
When these points are reflected in your script, how about the following modification?
Modified script:
Please set your sheet name and your range.
function onEdit(e) {
var { range } = e;
var sheet = range.getSheet();
if (sheet.getSheetName() == 'MySheet') {
var checkboxCells = sheet.getRange('MyRange');
var startRow = checkboxCells.getRow();
var endRow = startRow + checkboxCells.getNumRows() - 1;
var startCol = checkboxCells.getColumn();
var endCol = startCol + checkboxCells.getNumColumns() - 1;
var check = range.rowStart >= startRow && range.rowEnd <= endRow && range.columnStart >= startCol && range.columnEnd <= endCol;
if (check && range.isChecked() === null) {
range.insertCheckboxes();
}
}
}
In this modified script, when a cell is edited, when the edited cell is included in MyRange, it checks whether the edited cell is a checkbox when the edited cell is not a checkbox, the checkboxes are inserted into the edited cell.
Reference:
isChecked()

On edit function, Timestamp and dependent access on column to update in google sheet

Am trying to make it possible, After updated previous step use can update next step and i will get timestamp for all updates.
function onEdit(e) {
var range = e.range
var sheet = range.getSheet();
var sheetName = "Not Open";
var editedRow = range.getRow();
var editedColumn = range.getColumn();
var checkbox = sheet.getRange(editedRow, 45).getValue();
if (sheet.getName() == sheetName && editedColumn == 51 && editedRow > 2 && checkbox == false) {
Browser.msgBox("You Can't Complete This Task Befor Previous task Done");
e.range.setValue(e.oldValue);
}
addTimestamp(e);
}
function addTimestamp(e)
{
//variables
var startRow = 8;
var targetColumn45 = 45;
var targetColumn51 = 51;
var WS = "Not Open";
//get modified row and column
var row = e.range.getRow();
var col = e.range.getColumn();
if(col === targetColumn45 && row >= startRow && e.source.getActiveSheet().getName() === WS) {
var currentDate = new Date();
e.source.getActiveSheet().getRange(row, 43).setValue(currentDate);
e.range.setValue(e.oldValue);
}
if(col === targetColumn51 && row >= startRow && e.source.getActiveSheet().getName() === WS) {
var currentDate = new Date();
e.source.getActiveSheet().getRange(row, 49).setValue(currentDate);
}
}
I have to create one process having 10 steps to complete one work.
step 1,2,3 will start when new form submitted with new entry.
step 4,5,6 will start after completion of step 3.
continue......
end of process
At the end I will get total days to complete one task and delay time.

Google Sheets script - code optimization - one script, two sheets, same workbook

I have one workbook with multiple sheets and I've been running some simple scripts on two of those sheets (those sheets are basically copies of one another).
Once script creates a dropdown based on the value entered in one of the cells, while the second script adds a timestamp based on when the new dropdown was edited.
Initially I had two onEdit functions running on the first sheet.
Then I created a copy of these functions, with small amendments, to run on another sheet(same workbook)
Given that I don't really know how to have a separate script per worksheet I now have a one script with 4 similar onEdit functions.
Since I'm a total newbie I'm sure there's a better, more efficient way to write this code.
I'd appreciate your help in optimizing this.
function onEdit(e) {
addTimestamp(e);
addTimestamp2(e);
Dropdown(e);
Dropdown2(e);
}
function addTimestamp(e) {
var startRow = 2;
var targetColumn = 10;
var ws = "Tracker1";
var row = e.range.get.Row();
var col = e.range.getColumn();
if(col === targetColumn && row >= startRow && e.source.getActiveSheet().getName() === ws) {
var currentDate = new Date();
e.source.getActiveSheet().getRange(row,11).setValue(currentDate);
}
}
function addTimestamp2(e) {
var startRow = 2;
var targetColumn = 10;
var ws = "Tracker2";
var row = e.range.get.Row();
var col = e.range.getColumn();
if(col === targetColumn && row >= startRow && e.source.getActiveSheet().getName() === ws) {
var currentDate = new Date();
e.source.getActiveSheet().getRange(row,11).setValue(currentDate);
}
}
function Dropdown(){
var tabLists = "StatusFlow";
var tabValidation = "Tracker1"
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var datass = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(tabLists);
var activeCell = ss.getActiveCell();
if(activeCell.getColumn() == 9 && activeCell.getRow() > 1 && ss.getSheetName() == tabValidation){
activeCell.offset(o,1).clearContent().clearDataValidations();
var makes = datass.getRange(1,1,1, datass.getLastColumn()).getValues();
var makeIndex = makes[0].indexOf(activeCell.getValue()) +1;
if(makeIndex !=0) {
var validationRange = datass.getRange(2, makeIndex, datass.getLastRow());
var validationRule = SpreadsheetApp.newDataValidation().requireValueInRange(validationRange).setAllowInvalid(false).build();
activeCell.offset(0, 1).setDataValidation(validationRule);
}
}
}
function Dropdown2(){
var tabLists = "StatusFlow";
var tabValidation = "Tracker2"
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var datass = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(tabLists);
var activeCell = ss.getActiveCell();
if(activeCell.getColumn() == 9 && activeCell.getRow() > 1 && ss.getSheetName() == tabValidation){
activeCell.offset(o,1).clearContent().clearDataValidations();
var makes = datass.getRange(1,1,1, datass.getLastColumn()).getValues();
var makeIndex = makes[0].indexOf(activeCell.getValue()) +1;
if(makeIndex !=0) {
var validationRange = datass.getRange(2, makeIndex, datass.getLastRow());
var validationRule = SpreadsheetApp.newDataValidation().requireValueInRange(validationRange).setAllowInvalid(false).build();
activeCell.offset(0, 1).setDataValidation(validationRule);
}
}
}
here is a more efficient way to replace the two addTimestamp functions:
function onEdit(e) {
var activeSheet = e.source.getActiveSheet();
var activeSName = activeSheet.getName();
var row = e.range.get.Row();
var col = e.range.getColumn();
if ((activeSName == 'Tracker1' || activeSName == 'Tracker2') && col === 10 && row >= 2) {
activeSheet.getRange(row, 11).setValue(new Date());
}
}
You could give the two Dropdown functions a shot and see if you can do something similar. Nothing like learning-by-doing. :-D
Just be careful that in onEdit you are passing e to these Dropdown functions. But not using them in these functions.

Create a timestamp in a specific cell in Google Sheets

I'm trying to create a timestamp in a Google Sheet when a specific cell is edited. I need the timestamp to be added to cell B2 when cell A3 is edited. I also need the timestamp to be written as uppercase (in the format of 'FEBRUARY 20'). I have amended the date format in Google Sheets so it is displayed as month then year, but it also needs capitalising (Google Sheets is automatically formatting as 'February 20'). The code I have is
function onEdit(e) {
addTimestamp(e);
}
function addTimestamp(e){
//variables
var startRow = 3;
var targetColumn = 1;
var ws = "template";
//get modified row and column
var row = e.range.getRow();
var col = e.range.getColumn();
if(col === targetColumn && row >= startRow && e.source.getActiveSheet().getName() === ws){
var currentDate = new Date();
e.source.getActiveSheet().getRange(1,2).setValue(currentDate);
if(e.source.getActiveSheet().getRange(row,3),getValue() == ""){
e.source.getActiveSheet().getRange(row,3).setValue(currentDate);
} //END IF check if date created exists
} //END IF check column, row, worksheet
} //END function addTimestamp
Try this:
function onEdit(e) {
//e.source.toast('Entry');
var sh=e.range.getSheet();
if(sh.getName()!='************Your sheet name here*********')return;
if(e.range.columnStart==1 && e.range.rowStart==3) {
var M=['JANUARY','FEBRUARY','MARCH','APRIL','MAY','JUNE','JULY','AUGUST','SEPTEMBER','OCTOBER','NOVEMBER','DECEMBER'];
//e.source.toast('Flag1');
var ts= M[new Date().getMonth()] + " " + new Date().getDate();
//e.source.toast(ts);
sh.getRange(2,2).setValue(ts);
}
}

Can't delete an event in my google calendar using scripts

I made a spreadsheet where I can easily manage my events in my google Calendar.
In the spreadsheet Row 1 has the dates, Row 2 has the specifics of the appointment and Row 3 saves the eventId of the event created by the script.
Every week starts on a new row.
The script works like it should and looks like this:
function CalenderUpdate() {
var calId = "xxxxxxxxxxxxxxxx#group.calendar.google.com";
var descr = "";
var date
var titel
var sheet = SpreadsheetApp.getActiveSheet();
var Afspraak = sheet.getRange(2,1,3,5).getValues();
var cal = CalendarApp.getCalendarById(calId);
for (j=2;j<9;j=j+3){
Afspraak = sheet.getRange(j,1,3,5).getValues();
for (i=0; i<5; i++){
descr ="";
date = Afspraak[0][i];
titel = Afspraak[1][i];
if (titel == "A"){ descr = "Late 14:00 - 21:00";}
if (titel == "M"){ descr = "Early 6:00 - 14:00";}
if (Afspraak[1][i] != ""){
var event = cal.createAllDayEvent(titel,date,{description:descr});
sheet.getRange(j+2,i+1).setValue(event.getId());
}
}
}
}
Now I want a new function. If I edit something in the schedule, I want it to update in my calendar. So I added a function onEdit that would delete the event if one created on that day, and if necessary create a new.
I started with this code to delete the event if something is edited. But it doesn't delete the appointment and I can't figure out why.
function onEdit(e){
var ss = SpreadsheetApp.getActiveSheet();
var range = e.range;
var rij = range.getRow();
var col = range.getColumn();
var afspraakId = ss.getRange(rij+1,col).getValue();
if (rij % 3 == 0) { ss.getRange(1,1).setValue(afspraakId); }
var calId = "xxxxxxxxxxxxxxx#group.calendar.google.com";
var cal = CalendarApp.getCalendarById(calId);
var event = cal.getEventSeriesById(id);
event.deleteEventSeries();
}
Hope someone can help me?
EDIT:
I changed the onEdit(e) to onEditInstallable(e) but the script never get triggered.
Even if I add a trigger by the menu
What do I do wrong?
EDIT2:
I've done some editing on my script. This is the end result:
function test_onEdit() {
onEditInstallable({
user : Session.getActiveUser().getEmail(),
source : SpreadsheetApp.getActiveSpreadsheet(),
range : SpreadsheetApp.getActiveSpreadsheet().getActiveCell(),
value : SpreadsheetApp.getActiveSpreadsheet().getActiveCell().getValue(),
authMode : "LIMITED"
});
}
function onEditInstallable(e){
var ss = SpreadsheetApp.getActiveSheet();
var range = e.range;
var rij = range.getRow();
var col = range.getColumn();
if (rij % 3 == 0 && col < 8) {
var cal = CalendarApp.getCalendarById("xxxxxxxxxxxxxxxxxx#group.calendar.google.com");
var event
var geg = ["","",""];
var descr ="";
for (i = 0 ; i < 3 ; i++){ geg[i] = ss.getRange(rij-1+i,col).getValue();}
if (geg[2] != ""){
event = cal.getEventSeriesById(geg[2]);
event.deleteEventSeries();
ss.getRange(rij+1,col).setValue("");
}
if (geg[1] != ""){
event = cal.createAllDayEvent(geg[1],geg[0],{description:descr});
ss.getRange(rij+1,col).setValue(event.getId());
}
}
}
The script works if I run the test_OnEdit. But the onEditInstallable doesn't trigger automatic? I'm an amateur in programming and I don't understand much of this page. Hope someone can help me figure this out.
Your second edit is a good approach, I'd suggest to add a couple of logs in the script to check the condition values.
I'd rather use the comments for this but it would definitely be too long and hard to read so I use the 'answer' format.
function onEditInstallable(e){
var ss = SpreadsheetApp.getActiveSheet();
var range = e.range;
var rij = range.getRow();
var col = range.getColumn();
Logger.log('rij = '+rij+' col = '+col);
if (rij % 3 == 0 && col < 8) {
var cal = CalendarApp.getCalendarById("xxxxxxxxxxxxxxxxxx#group.calendar.google.com");
var event
var geg = ["","",""];
var descr ="";
for (i = 0 ; i < 3 ; i++){ geg[i] = ss.getRange(rij-1+i,col).getValue();}
Logger.log('geg[2] = '+geg[2]);
if (geg[2] != ""){
event = cal.getEventSeriesById(geg[2]);
event.deleteEventSeries();
ss.getRange(rij+1,col).setValue("");
}
if (geg[1] != ""){
event = cal.createAllDayEvent(geg[1],geg[0],{description:descr});
ss.getRange(rij+1,col).setValue(event.getId());
}
}
}
I used this last piece of code and linked the test_onEdit script to a button in the spreadsheet. On the first time testing it from there Google gave a pop-up asking for extra authorizations. From then on everything works like a charm.
Now my spreadsheet automatically edits my agenda if I change something in the spreadsheet.
Thanks for the help everyone.
function test_onEdit() {
onEditInstallable({
user : Session.getActiveUser().getEmail(),
source : SpreadsheetApp.getActiveSpreadsheet(),
range : SpreadsheetApp.getActiveSpreadsheet().getActiveCell(),
value : SpreadsheetApp.getActiveSpreadsheet().getActiveCell().getValue(),
authMode : "LIMITED"
});
}
function onEditInstallable(e){
var ss = SpreadsheetApp.getActiveSheet();
var range = e.range;
var rij = range.getRow();
var col = range.getColumn();
Logger.log('rij = '+rij+' col = '+col);
if (rij % 3 == 0 && col < 8) {
var cal = CalendarApp.getCalendarById("xxxxxxxxxxxxxxxxxx#group.calendar.google.com");
var event
var geg = ["","",""];
var descr ="";
for (i = 0 ; i < 3 ; i++){ geg[i] = ss.getRange(rij-1+i,col).getValue();}
Logger.log('geg[2] = '+geg[2]);
if (geg[2] != ""){
event = cal.getEventSeriesById(geg[2]);
event.deleteEventSeries();
ss.getRange(rij+1,col).setValue("");
}
if (geg[1] != ""){
event = cal.createAllDayEvent(geg[1],geg[0],{description:descr});
ss.getRange(rij+1,col).setValue(event.getId());
}
}
}
Try this:
function deleteEvent(event) {
if (typeof event != 'undefined') {
Logger.log("Deleting event %s", event.getTitle())
event.deleteEvent()
}
}
function deleteEvents(eventCal,startTime,endTime,title){
// var oldEvents = eventCal.getEvents(startTime, endTime, {search: title});
var oldEvents = eventCal.getEvents(startTime, endTime);
Logger.log("oldEvents %s", oldEvents);
for (var j = 0; j < oldEvents.length; j++){
Logger.log("oldEvents[j] %s", oldEvents[j]);
deleteEvent(oldEvents[j]);
}
}