I am using Google Sheets and I have two functions onEdit and onCommsEdit that work great and add a timestamp to their respective sheets. If I copy and paste one of them exactly and give a new function name - the additional functionality will not seem to work.
Am I ordering things incorrectly? Or should I be naming all sheets in the same function? (I had created duplicates because the write to columns varied by the sheet.)
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{name:"Last Row", functionName:"goto_last"}];
sheet.addMenu("Shortcuts", entries);
myFunction();
};
function goto_last() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var mysheet = ss.getActiveSheet();
var lastrow = mysheet.getLastRow();
mysheet.setActiveCell(mysheet.getDataRange().offset(lastrow-1, 0, 1, 1));
};
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
if( s.getName() == "Primary Log" ) {
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-08:00", "yyyy-MM-dd, hh:mm:ss");
SpreadsheetApp.getActiveSheet().getRange('M' + row.toString()).setValue(time);
SpreadsheetApp.getActiveSheet().getRange("N" + row.toString()).setValue(user);
}
};
};
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var mysheet = ss.getActiveSheet();
var lastrow = mysheet.getLastRow();
mysheet.setActiveCell(mysheet.getDataRange().offset(lastrow-1, 0, 1, 1));
};
function onCommsEdit() {
var s = SpreadsheetApp.getActiveSheet();
if( s.getName() == "Received Report" ) {
var r = s.getActiveCell();
var user = Session.getActiveUser().getEmail();
if( r.getColumn() != 11 ) { //checks the column
var row = r.getRow();
var time = new Date();
time = Utilities.formatDate(time, "GMT-08:00", "yyyy-MM-dd, hh:mm:ss");
SpreadsheetApp.getActiveSheet().getRange('K' + row.toString()).setValue(time);
SpreadsheetApp.getActiveSheet().getRange("L" + row.toString()).setValue(user);
}
};
};
You must create a trigger in order for a function to be called automatically.
It is not recommended to have multiple functions all called with an onEdit condition, as the execution order is not well defined. I also do not recommend naming a function that requires an installed trigger such that it matches the corresponding simple trigger -- in other words, a function that requires authorization scopes and is to be run after the spreadsheet values are modified should not be called onEdit(e), as that is the name of function which activates the simple trigger. If your function does not require authorization scopes, then you can use the simple trigger.
As far as your program design, you should use flow control. Rather than multiple functions, simply branching is sufficient:
function calledOnEdit(e) {
if(!e) { throw new Error("This function requires an event object"); }
// Use the event object rather than lookups that assume the active cell was the edited cell:
var s = e.range.getSheet();
var row = e.range.getRow();
var col = e.range.getColumn();
if( s.getName() == "Primary Log" && col != 13 ) { //checks the column
logTimestamp(s, "M" + row + ":N" + row);
} else if( s.getName() == "Received Report" && col != 11 ) { //checks the column
logTimestamp(s, "K" + row + ":L" + row);
}
}
function logTimestamp(sheet, a1ref) {
var user = Session.getActiveUser().getEmail();
var time = Utilities.formatDate(new Date(), "GMT-08:00", "yyyy-MM-dd, hh:mm:ss");
sheet.getRange(a1ref).setValues([[time, user]]);
}
Related
I need some support. I am a newbie and I try to build a function which checks 2 entries in different sheets (both in one spreadsheet) if the condition "state" is true. If so the function has to set a value. If the condition is false, the function has to put a different value.
Currently the function set alway the same value (13:00) instead of the stored values.
I hope an one can help. Code below:
//Create an UI menu
function onOpen() {
var ui = SpreadsheetApp.getUi().createMenu('⏰');
ui.addItem('🔄 Update ETAs','etaCheck')
ui.addToUi();
}
function etaCheck(){
// Defined variabels
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ds = ss.getSheetByName('support ETA');
var ms = ss.getSheetByName('KPI Tracker 22');
var eta = ds.getRange('G2:G').getValues();
var tms1 = ds.getRange('E2:E').getValues();
var tms2 = ms.getRange('O2:O').getValues();
var state = ds.getRange('F2:F').getValues();
// If statement
if(tms1 === tms2 && state === 'Update'){
ms.getRange('R2').setValue(eta)
}else{
ms.getRange('R2').setValue(eta)
}
}
I can't be sure but I think this is closer to what you desire
function etaCheck() {
const ss = SpreadsheetApp.getActive();
const sh1 = ss.getSheetByName('support ETA');
const sh2 = ss.getSheetByName('KPI Tracker 22');
const o = sh2.getRange(2, 18, sh2.getLastRow() - 1).getValues();
const eta = sh1.getRange('G2:G' + sh1.getLastRow()).getValues().flat();
const tms1 = sh1.getRange('E2:E' + sh1.getLastRow()).getValues().flat();
const tms2 = sh2.getRange('O2:O' + sh2.getLastRow()).getValues().flat();
const state = sh1.getRange('F2:F' + sh1.getLastRow()).getValues().flat();
tms1.forEach((e,i) => {
if(e == tms2[i] && state[i] == 'Update') {
o[i][0] = eta[i]
sh2.getRange(i + 2, 18).setValue(eta[i]);
} else {
sh2.getRange(i + 2, 18).setValue(eta[i]);//This does not make much sense since you are doing the same thing in both cases
}
})
}
I created two google sheet with an exchange of data from sheet 1 to 2 with the IMPORTRANGE function.
I would like to save my data on the second sheet while importing. But I don't know how.
Below is my code which allows me to delete the lines as soon as 30 days have passed.
function onEdit() {
// Sheet the data is on.
var SHEET = "Copie de TF VBX";
// The value that will cause the row to hide.
var VALUE = "date";
// The column we will be using
var COLUMN_NUMBER = 12
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activeSheet = ss.getActiveSheet();
var cell = ss.getActiveCell()
var cellValue = cell.getValue();
var colonne = cell.getColumn();
var ligne = cell.getRow();
var date2 = new Date(Date());
var date1 = new Date(cellValue);
// différence des heures
var time_diff = date2.getTime() - date1.getTime();
// différence de jours
var days_Diff = time_diff / (1000 * 3600 * 24);
//Ensure on correct sheet.
if(SHEET == activeSheet.getName()){
//Ensure we are looking at the correct column.
if(colonne == COLUMN_NUMBER){
//If the cell matched the value we require,hide the row.
if(days_Diff>31){
activeSheet.deleteRow(ligne)
//Browser.msgBox(days_Diff)
};
};
};
}
Thank you for your help.
function onEdit(e) {
const sh = e.range.getSheet();
if (sh.getName() = "Copie de TF VBX" && e.range.columnStart == 12 && e.value) {
const td = new Date()
const thd = new Date(td.getFullYear(), td.getMonth(), td.getDate() - 31).valueOf();
const date1v = new Date(e.value).valueOf();
if (date1v > thd) {
sh.deleteRow(e.range.rowStart);
e.source.toast(DiffInDays(td,new Date(e.value));
}
}
}
function DiffInDays(Day1,Day2) {
if(Day1 && Day2 && (Object.prototype.toString.call(Day1) === '[object Date]') && (Object.prototype.toString.call(Day2) === '[object Date]')) {
var day=86400000;
var t1=new Date(Day1).valueOf();
var t2=new Date(Day2).valueOf();
var d=Math.abs(t2-t1);
var days=Math.floor(d/day);
//Logger.log(days);
return days;
} else {
throw 'Invalid Inputs';
}
}
I'm very new to scripts and trying to get the best out of and onEdit() function to track changes made on a collaborative spreadsheet.
The script seems to run well given that a line is added to the Changelog sheet every time a change is made by any user at all on the sheet.
However, it only sometimes registers the data i'm seeking, and most of the times registers a line which is a copy of the heading: see here
Do I have something wrong with authorizations here? Or is it something else?
Thank you so, so much!
--
Here is the detail of the script:
function onEdit(e) {
var changelogSheetName = "Changelog";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cell = SpreadsheetApp.getActiveRange();
var timestamp = new Date();
var currentSheet = ss.getActiveSheet();
var currentSheetName = currentSheet.getName();
var previousValue = e.oldValue;
var newValue = cell.getValue();
var typeChange = "Edit";
if (currentSheetName == changelogSheetName) return;
var changelogSheet = ss.getSheetByName(changelogSheetName);
if (changelogSheet == null) {changelogSheet = ss.insertSheet(changelogSheetName, ss.getNumSheets());}
changelogSheet.getRange('A1:G1').setBackground('#E0E0E0');
changelogSheet.appendRow(["Timestamp", "Sheet", "Cell", "Type", "Old Value", "New Value", "User"]);
changelogSheet.deleteColumns(8,19);
changelogSheet.setFrozenRows(1);
changelogSheet.setColumnWidth(1, 170);
changelogSheet.setColumnWidth(7, 170);
changelogSheet.protect();
var user = Session.getEffectiveUser().getEmail();
if (previousValue == null){typeChange = "Add";} else if (newValue == "") {typeChange = "Remove";}
changelogSheet.appendRow([timestamp, currentSheetName, cell.getA1Notation(), typeChange, previousValue, newValue, user]);
}
This part of your code should be inside your if (changelogSheet == null) statement since you only want this part to be executed if the sheet ChangeLog does not exist. This also causes the script to write headers every time an event occurs.
changelogSheet.getRange('A1:G1').setBackground('#E0E0E0');
changelogSheet.appendRow(["Timestamp", "Sheet", "Cell", "Type", "Old Value", "New Value", "User"]);
changelogSheet.deleteColumns(8,19);
changelogSheet.setFrozenRows(1);
changelogSheet.setColumnWidth(1, 170);
changelogSheet.setColumnWidth(7, 170);
changelogSheet.protect();
Here I edited your code, fixed some logic and utilize to use of event object(e):
function onEdit(e) {
var ss = e.source.getActiveSheet();
var editedSheet = ss.getSheetName();
var changelogSheetName = "Changelog";
if (editedSheet == changelogSheetName) return;
var changelogSheet = e.source.getSheetByName(changelogSheetName);
if (!changelogSheet) {
changelogSheet = e.source.insertSheet(changelogSheetName, e.source.getNumSheets());
changelogSheet.appendRow(["Timestamp", "Sheet", "Cell", "Type", "Old Value", "New Value", "User"]);
changelogSheet.getRange('A1:G1').setBackground('#E0E0E0');
changelogSheet.deleteColumns(8, 19);
changelogSheet.setFrozenRows(1);
changelogSheet.setColumnWidth(1, 170);
changelogSheet.setColumnWidth(7, 170);
changelogSheet.protect();
}
var timestamp = new Date();
var previousValue = e.oldValue;
var newValue = e.value;
var typeChange = "Edit";
var cell = e.range.getA1Notation();
var user = Session.getEffectiveUser().getEmail();
if (previousValue == null) {
typeChange = "Add";
} else if (newValue == "") {
typeChange = "Remove";
}
changelogSheet.appendRow([timestamp, editedSheet, cell, typeChange, previousValue, newValue, user]);
}
Edited Sheet:
Output:
Reference:
Event Objects
This is what I've got:
function onEdit(e) {
var range = e.range;
var val = range.getValue();
var row = range.getRow();
var col = range.getColumn();
var shift = 1;
var ss = SpreadsheetApp.getActiveSheet().getRange(row, (col+shift));
if (col == 3){
ss.setValue(new Date()).setNumberFormat("MM/dd/yyy hh:mm:ss");
}
if (val == ""){
ss.setValue("").setNumberFormat("MM/dd/yyy hh:mm:ss");
}
}
This is what is happening:
However, when I edit a cell in barcode, it doesn't update the timestamp...
function onEdit(e) {
//e.source.toast("Entry");
//console.log(JSON.stringify(e));
const sh=e.range.getSheet();
if(sh.getName()=="Sheet1" && e.range.columnStart==3 && e.value) {
e.range.offset(0,1).setValue(Utilities.formatDate(new Date(),Session.getScriptTimeZone(),"MM/dd/yyyy HH:mm:ss"));
}
}
I presume you wouldn't want to this for all sheets but I could be wrong.
I have a Google Apps Script that has been running for 3 months and starting a few weeks ago I'm getting a "Service Error" on the Appendrow function which I've bolded below. Any ideas on how to fix this?
function updateACOPS2(){
var ss = SpreadsheetApp.openById(".....")
var sheetSubmission = ss.getSheetByName("Sheet8");
var dataSubmission = sheetSubmission.getDataRange().getValues();
var lastColSubmission = sheetSubmission.getLastColumn();
var ssActive = SpreadsheetApp.openById("....")
var sheetActive = ssActive.getSheetByName("AcopsAll");
var sheetMain = ssActive.getSheetByName("Sheet1");
var dataActive = sheetActive.getDataRange().getValues();
var lastrow = sheetActive.getLastRow();
for(var i = 1; i < dataSubmission.length && dataSubmission[i][2] != ""; i++){
var currentIDSubmission = dataSubmission[i][2] + dataSubmission[i][3];
var checkGotMatch = false;
var toCopyRow = sheetSubmission.getRange(i+1,1,1,71);
// copy entire row for new record
Logger.log(currentIDSubmission);
// if there is a matching record flag as matched
for(var j = 1; j<dataActive.length; j++){
var currentIDActive = dataActive[j][2] + dataActive[j][3];
var currentIDSub = dataSubmission[i][2];
if(currentIDSub != '' && currentIDSubmission == currentIDActive){
checkGotMatch = true;
Logger.log(currentIDActive);
break;
}
}
// if it is a new record Append entire row
if(currentIDSub != '' && checkGotMatch == false){
**sheetMain.appendRow(toCopyRow.getValues()[0]);**
}
}
SpreadsheetApp.flush();
ss.toast("ACOPS Active has been updated.", "Complete");
}
In appendRow you need to pass an array so update your appendRow and try
sheetMain.appendRow([toCopyRow.getValues()[0]])