I have a strange script issue I was hoping someone could help me with -- I have 2 different sheets with timestamps that update when the neighboring cell is initialed. The scripts for both sheets are exactly the same (with different sheet names of course) and are not intended to interact, but one of them keeps copying over to the other.
Whenever someone initials/timestamps sheet 1, the script runs successfully on sheet 1 but also updates the same cell on sheet 2. If the cell doesn't exist, extra rows get added to create it. This copying doesn't happen the other way around.
Is there anything I can do to stop this?
Code for sheet 1:
function onEdit(event)
{
var timezone = "PST";
var timestamp_format = "MM-dd-yyyy hh:mm:ss"; // Timestamp Format.
var updateColName = "Initials";
var timeStampColName = "Last Updated";
var sheet = event.source.getSheetByName('WC Labs'); //Name of the sheet where you want to run this script.
var actRng = event.source.getActiveRange();
var editColumn = actRng.getColumn();
var index = actRng.getRowIndex();
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
var dateCol = headers[0].indexOf(timeStampColName);
var updateCol = headers[0].indexOf(updateColName); updateCol = updateCol+1;
if (dateCol > -1 && index > 1 && editColumn == updateCol) { // only timestamp if 'Last Updated' header exists, but not in the header row itself!
var cell = sheet.getRange(index, dateCol + 1);
var date = Utilities.formatDate(new Date(), timezone, timestamp_format);
cell.setValue(date);
}
}
Code for sheet 2:
function onEdit(event)
{
var timezone = "EST";
var timestamp_format = "MM-dd-yyyy hh:mm:ss"; // Timestamp Format.
var updateColName = "Initials";
var timeStampColName = "Last Updated";
var sheet = event.source.getSheetByName('EC Labs'); //Name of the sheet where you want to run this script.
var actRng = event.source.getActiveRange();
var editColumn = actRng.getColumn();
var index = actRng.getRowIndex();
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
var dateCol = headers[0].indexOf(timeStampColName);
var updateCol = headers[0].indexOf(updateColName); updateCol = updateCol+1;
if (dateCol > -1 && index > 1 && editColumn == updateCol) { // only timestamp if 'Last Updated' header exists, but not in the header row itself!
var cell = sheet.getRange(index, dateCol + 1);
var date = Utilities.formatDate(new Date(), timezone, timestamp_format);
cell.setValue(date);
}
}
Keep things DRY: if there are two functions that do the same thing, you only need one.
getSheet method allows you to get the sheet that contains the currently edited Range - use it to acquire the reference to the currently edited sheet.
Use strict equality comparison (it will not change anything in your case, but builds a useful habit that will save you debugging time).
Exit as early as possible: if statements should handle edge cases, not main logic.
Use the newer V8 runtime (the snippet below uses ES6 syntax).
/**
* #param {{
* range : GoogleAppsScript.Spreadsheet.Range,
* timezone : (string|"PST")
* }} param0
*/
function onEdit({ range, timezone = "PST" }) {
const sheet = range.getSheet();
const timestamp_format = "MM-dd-yyyy hh:mm:ss";
const updateColName = "Initials";
const timeStampColName = "Last Updated";
const editColumn = range.getColumn();
const editIndex = range.getRowIndex();
const [header] = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
const dateCol = header.indexOf(timeStampColName);
const updateCol = header.indexOf(updateColName) + 1;
if (dateCol < 0 && editIndex <= 1 && editColumn !== updateCol) { return; }
const cell = sheet.getRange(editIndex, dateCol + 1);
const date = Utilities.formatDate(new Date(), timezone, timestamp_format);
cell.setValue(date);
}
References
onEdit event object structure
The onEdit() function in both files is getting event.source.getActiveRange(); as the active range. Since you don't specify a particular sheet, whichever cell you are editing becomes active regardless of which sheet/tab it belongs.
Try to replace this line:
var actRng = event.source.getActiveRange();
in both files with the following:
var actRng = event.source.getSheetByName('WC Labs').getActiveRange();
and
var actRng = event.source.getSheetByName('EC Labs').getActiveRange();
respectively.
Code for sheet 1:
function onEdit(event)
{
var timezone = "PST";
var timestamp_format = "MM-dd-yyyy hh:mm:ss"; // Timestamp Format.
var updateColName = "Initials";
var timeStampColName = "Last Updated";
var sheet = event.source.getSheetByName('WC Labs'); //Name of the sheet where you want to run this script.
var actRng = event.source.getSheetByName('WC Labs').getActiveRange();
var editColumn = actRng.getColumn();
var index = actRng.getRowIndex();
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
var dateCol = headers[0].indexOf(timeStampColName);
var updateCol = headers[0].indexOf(updateColName); updateCol = updateCol+1;
if (dateCol > -1 && index > 1 && editColumn == updateCol) { // only timestamp if 'Last Updated' header exists, but not in the header row itself!
var cell = sheet.getRange(index, dateCol + 1);
var date = Utilities.formatDate(new Date(), timezone, timestamp_format);
cell.setValue(date);
}
}
Code for sheet 2:
function onEdit(event)
{
var timezone = "EST";
var timestamp_format = "MM-dd-yyyy hh:mm:ss"; // Timestamp Format.
var updateColName = "Initials";
var timeStampColName = "Last Updated";
var sheet = event.source.getSheetByName('EC Labs'); //Name of the sheet where you want to run this script.
var actRng = event.source.getSheetByName('EC Labs').getActiveRange();
var editColumn = actRng.getColumn();
var index = actRng.getRowIndex();
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
var dateCol = headers[0].indexOf(timeStampColName);
var updateCol = headers[0].indexOf(updateColName); updateCol = updateCol+1;
if (dateCol > -1 && index > 1 && editColumn == updateCol) { // only timestamp if 'Last Updated' header exists, but not in the header row itself!
var cell = sheet.getRange(index, dateCol + 1);
var date = Utilities.formatDate(new Date(), timezone, timestamp_format);
cell.setValue(date);
}
}
Related
I'm trying to make an Entry/Exit logbook, where staff would tag their ID cards to the card-reader at the entrance, which will populate a cell in column A, and this will trigger the script to create a day/time stamp.
{
function activeSheetName()
{
return
SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName();
}
{
var timezone = "GMT+7";
var timestamp_format = "MM/dd/yyyy HH:mm:ss"; // Timestamp Format.
var updateColName = "CardID";
var timeStampColName = "Date/Time";
var sheet = event.source.getSheetByName('Current'); //Name of the sheet where you want to run this script.
var actRng = event.source.getActiveRange();
var actSheet = event.source.getActiveSheet();
var actSheetName = actSheet.getSheetName();
var updateSheetName = sheet.getSheetName();
var editColumn = actRng.getColumn();
var index = actRng.getRowIndex();
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
var dateCol = headers[0].indexOf(timeStampColName);
var updateCol = headers[0].indexOf(updateColName); updateCol = updateCol+1;
if (dateCol > -1 && index > 1 && editColumn == updateCol && actSheetName == updateSheetName) { // only timestamp if ‘Last Updated’ header exists, but not in the header row itself!
var cell = sheet.getRange(index, dateCol + 1);
var date = Utilities.formatDate(new Date(), timezone, timestamp_format);
cell.setValue(date);
}
}
}
The problem is when the card is tagged, the cursor stays in the cell, so I need to hit enter for it to move down. Can I edit the script above for cursor to move one cell down automatically, as soon as the ID card is read by the reader? Please help, I've tried a separate jump down script and edit this one, but nothing worked so far. Thanks!
Example Logbook
If you mean mouse cursor, then I don't think you can do it via GAS. But if I understand you correctly, you want to activate the next cell in Column A after value was set. To do that, add method sheet.getRange(index+1,1).activate(); after you set value.
i found this great formula that works so great on my need, sorry i forgot it original source
The Original Code is move the entire Row if it found "X" on Columns 21 and copy the entire row to sheet with same name as col 22 and delete the Entire row
1st Question,
instead the delete entire row, i need it only to clear certains Columns, for example it only clear content Columns 3, 4, 10 and 12 only << Solved thanks to idfurw
2nd Question,
how to lock this script to only a certain sheet?
here the new script base on update from idfurw
Main Script
function onEdit(e) {
// see Sheet event objects docs
// https://developers.google.com/apps-script/guides/triggers/events#google_sheets_events
var ss = e.source;
var s = e.range.getSheet();
if (s.getName() == 'Form');
var r = e.range;
// to let you modify where the action and move columns are in the form responses sheet
var actionCol = 21;
var nameCol = 22;
// Get the row and column of the active cell.
var rowIndex = r.getRowIndex();
var colIndex = r.getColumnIndex();
// Get the number of columns in the active sheet.
// -1 to drop our action/status column
var colNumber = s.getLastColumn()-1;
// if our action/status col is changed to ok do stuff
if (e.value == "XX" && colIndex == actionCol) {
// get our target sheet name - in this example we are using the priority column
var targetSheet = s.getRange(rowIndex, nameCol).getValue();
// if the sheet exists do more stuff
if (ss.getSheetByName(targetSheet)) {
// set our target sheet and target range
var targetSheet = ss.getSheetByName(targetSheet);
var targetRange = targetSheet.getRange(targetSheet.getLastRow()+1, 1, 1, colNumber);
// get our source range/row
var sourceRange = s.getRange(rowIndex, 1, 1, colNumber);
// new sheets says: 'Cannot cut from form data. Use copy instead.'
sourceRange.copyTo(targetRange);
// ..but we can still delete the row after
const cols = [6, 7, 8, 12,14,16,17,19,20,21];
for (const col of cols) {
s.getRange(rowIndex, col).clearContent();
}
// or you might want to keep but note move e.g. r.setValue("moved");
}
}
}
Time Stamp Script
function onEdit(event)
{
var timezone = "GMT+7";
var time_format = "dd-MM-yyyy"; // Timestamp Format.
var updateColName = "Pasien";
var timeStampColName = "Tgl Keluar";
var sheet = event.source.getSheetByName('Form'); //Name of the sheet where you want to run this script.
var actRng = event.source.getActiveRange();
var editColumn = actRng.getColumn();
var index = actRng.getRowIndex();
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
var dateCol = headers[0].indexOf(timeStampColName);
var updateCol = headers[0].indexOf(updateColName); updateCol = updateCol+1;
if (dateCol > -1 && index > 1 && editColumn == updateCol)
{ // only timestamp if 'Last Updated' header exists, but not in the header row itself!
if (sheet.getRange(index, updateCol).isBlank()) {
sheet.getRange(index, dateCol + 1).clearContent();
}
else
var cell = sheet.getRange(index, dateCol + 1);
var date = Utilities.formatDate(new Date(), timezone, time_format);
cell.setValue(date);
}
}
Remove this line to disable deleting row:
s.deleteRow(rowIndex);
Replace with the following to clear content of specified cols:
const cols = [3, 4, 10, 12];
for (const col of cols) {
s.getRange(rowIndex, col).clearContent();
}
To limit the function to a particular sheet:
var s = e.range.getSheet();
/* add it after the above line */
if (s.getName() !== 'Name of sheet') { return; }
Need help on combining these two script. Im totally newbie in this thing. They are
Main.gs
whenput 'XX' on U Column (21st col) then it copy the whole row to a sheet with same name as V Column (22nd col). Then it delete certain columns (for example 6, 7, 8, 12,14,16,17,19,20,21)
function onEdit(e) {
var ss = e.source;
var s = e.range.getSheet();;
var r = e.range;
// to let you modify where the action and move columns are in the form responses sheet
var actionCol = 21;
var nameCol = 22;
// Get the row and column of the active cell.
var rowIndex = r.getRowIndex();
var colIndex = r.getColumnIndex();
// Get the number of columns in the active sheet.
// -1 to drop our action/status column
var colNumber = s.getLastColumn()-1;
// if our action/status col is changed to ok do stuff
if (e.value == "XX" && colIndex == actionCol) {
// get our target sheet name - in this example we are using the priority column
var targetSheet = s.getRange(rowIndex, nameCol).getValue();
// if the sheet exists do more stuff
if (ss.getSheetByName(targetSheet)) {
// set our target sheet and target range
var targetSheet = ss.getSheetByName(targetSheet);
var targetRange = targetSheet.getRange(targetSheet.getLastRow()+1, 1, 1, colNumber);
// get our source range/row
var sourceRange = s.getRange(rowIndex, 1, 1, colNumber);
// new sheets says: 'Cannot cut from form data. Use copy instead.'
sourceRange.copyTo(targetRange);
// ..but we can still delete the row after
const cols = [6, 7, 8, 12,14,16,17,19,20,21];
for (const col of cols) {
s.getRange(rowIndex, col).clearContent();
}
// or you might want to keep but note move e.g. r.setValue("moved");
}
}
}
and
TimeStamp.gs
when type a word at "Pasien" Col, at the same row it will add date to "Tgl Keluar" col and when delete that word, it also clear content
function onEdit(event)
{
var timezone = "GMT+7";
var time_format = "dd-MM-yyyy"; // Timestamp Format.
var updateColName = "Pasien";
var timeStampColName = "Tgl Keluar";
var sheet = event.source.getSheetByName('Form'); //Name of the sheet where you want to run this script.
var actRng = event.source.getActiveRange();
var editColumn = actRng.getColumn();
var index = actRng.getRowIndex();
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
var dateCol = headers[0].indexOf(timeStampColName);
var updateCol = headers[0].indexOf(updateColName); updateCol = updateCol+1;
if (dateCol > -1 && index > 1 && editColumn == updateCol)
{ // only timestamp if 'Last Updated' header exists, but not in the header row itself!
if (sheet.getRange(index, updateCol).isBlank()) {
sheet.getRange(index, dateCol + 1).clearContent();
}
else
var cell = sheet.getRange(index, dateCol + 1);
var date = Utilities.formatDate(new Date(), timezone, time_format);
cell.setValue(date);
}
}
This my combined onEdit
but i still dont understand about nested
function onEdit(event) {
first(event);
second(event);
}
function first(event)
{
var ss = e.source;
var s = e.range.getSheet();;
if (s.getName() !== 'Form')
var r = e.range;
// to let you modify where the action and move columns are in the form responses sheet
var actionCol = 21;
var nameCol = 22;
// Get the row and column of the active cell.
var rowIndex = r.getRowIndex();
var colIndex = r.getColumnIndex();
// Get the number of columns in the active sheet.
// -1 to drop our action/status column
var colNumber = s.getLastColumn()-1;
// if our action/status col is changed to ok do stuff
if (e.value == "XX" && colIndex == actionCol) {
// get our target sheet name - in this example we are using the priority column
var targetSheet = s.getRange(rowIndex, nameCol).getValue();
// if the sheet exists do more stuff
if (ss.getSheetByName(targetSheet)) {
// set our target sheet and target range
var targetSheet = ss.getSheetByName(targetSheet);
var targetRange = targetSheet.getRange(targetSheet.getLastRow()+1, 1, 1, colNumber);
// get our source range/row
var sourceRange = s.getRange(rowIndex, 1, 1, colNumber);
// new sheets says: 'Cannot cut from form data. Use copy instead.'
sourceRange.copyTo(targetRange);
// ..but we can still delete the row after
const cols = [6, 7, 8, 12,14,16,17,19,20,21];
for (const col of cols) {
s.getRange(rowIndex, col).clearContent();
}
// or you might want to keep but note move e.g. r.setValue("moved");
}
}
}
function second(event)
{
var timezone = "GMT+7";
var time_format = "dd-MM-yyyy"; // Timestamp Format.
var updateColName = "Pasien";
var timeStampColName = "Tgl Keluar";
var sheet = event.source.getSheetByName('Form'); //Name of the sheet where you want to run this script.
var actRng = event.source.getActiveRange();
var editColumn = actRng.getColumn();
var index = actRng.getRowIndex();
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
var dateCol = headers[0].indexOf(timeStampColName);
var updateCol = headers[0].indexOf(updateColName); updateCol = updateCol+1;
if (dateCol > -1 && index > 1 && editColumn == updateCol)
{ // only timestamp if 'Last Updated' header exists, but not in the header row itself!
if (sheet.getRange(index, updateCol).isBlank()) {
sheet.getRange(index, dateCol + 1).clearContent();
}
else
var cell = sheet.getRange(index, dateCol + 1);
var date = Utilities.formatDate(new Date(), timezone, time_format);
cell.setValue(date);
}
}
The third code would be the simplest solution in case it complete within the time limit.
Otherwise, you need to optimize the code by:
replacing call of SpreadsheetApp by event object
removing duplicates among the two child functions
using if, boolean (flag), return to minimize executions
You need to know you code well in other to do either of these.
I dare not rewrite the code entirely. Just in order to make it a bit faster I'd propose to change this lines (in the third example):
const cols = [6, 7, 8, 12,14,16,17,19,20,21];
for (const col of cols) {
s.getRange(rowIndex, col).clearContent();
}
to this:
// cols to clean
const cols = [6, 7, 8, 12, 14, 16, 17, 19, 20, 21];
// get an array from the row
var row_to_clean = s.getRange(rowIndex, 6, rowIndex, 21).getValues();
// clean the array
for (let c of cols) row_to_clean[0][c-6] = ''; // col 6 is array[0][0]
// set values of the array back on the row
s.getRange(rowIndex, 6, rowIndex, 21).setValues(row_to_clean);
It will reduce calls to the server from 10 clearContents() to 2 getValues() + setValues() for every edited row.
I'm trying to combine two scripts to run simultaneously but I can't get both of them to run. Below are the two separate scripts.
function onEdit(event) {
var sheet = event.source.getActiveSheet();
var editedCell = sheet.getActiveCell();
var columnToSortBy = 7;
var tableRange = "A2:T399"; // What to sort.
if(editedCell.getColumn() == columnToSortBy){
var range = sheet.getRange(tableRange);
range.sort( { column : columnToSortBy, ascending: false } );
}
}
and
function onEdit(event)
{
var timezone = "GMT-5";
var timestamp_format = "MM-dd-yyyy"; // Timestamp Format.
var updateColName = "Parent Sign-Out";
var timeStampColName = "Timestamp";
var sheet = event.source.getSheetByName('Area Check-in'); //Name of the sheet where you want to
run this script.
var actRng = event.source.getActiveRange();
var editColumn = actRng.getColumn();
var index = actRng.getRowIndex();
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
var dateCol = headers[0].indexOf(timeStampColName);
var updateCol = headers[0].indexOf(updateColName); updateCol = updateCol+1;
if (dateCol > -1 && index > 1 && editColumn == updateCol) { // only timestamp if 'Last Updated'
header exists, but not in the header row itself!
var cell = sheet.getRange(index, dateCol + 1);
var date = Utilities.formatDate(new Date(), timezone, timestamp_format);
cell.setValue(date);
}
}
I'm not sure if I need to name them individually. And if so, how would I add the names?
function onEdit(e) {
var sh=e.range.getSheet();
if(sh.getName()=='NameOfSheetYouWantThisToWorkOn') {
if(e.range.columnStart==7) {
e.range.getSheet().getRange("A2:T399").sort({column:7,ascending:false});
}
}
if(sh.getName()=='Area Check-in') {
var headers=sh.getRange(1,1,1,sh.getLastColumn()).getValues()[0];
var dateCol=headers.indexOf("Timestamp")+1;
var updateCol=headers.indexOf("Parent Sign-Out")+1;
if (dateCol>0 && e.range.rowStart>1 && e.range.columnStart == updateCol) {
sh.getRange(e.range.rowStart,dateCol).setValue(Utilities.formatDate(new Date(), "GMT-5", "MM-dd-yyyy"));
}
}
}
function onEdit(event)
{
var timezone = "GMT-6";
var timestamp_format = "HH:mm:ss"; // Timestamp Format.
var sheet = event.source.getActiveSheet();//Name of the sheet where you want to run this script.
var actRng = event.source.getActiveRange();
var editColumn = actRng.getColumn();
var index = actRng.getRowIndex();
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
var dateCol = headers[0].indexOf(timeStampColName);
var updateCol = headers[0].indexOf(updateColName); updateCol = updateCol+1;
var updateColName = sheet.getRange( 1, editColumn).getValue ();
var timeStampColName = "null";
if (updateColName == "PACK STARTED BY") {timeStampColName = "Pack Start";}
if (dateCol > -1 && index > 1 && editColumn == updateCol) { // only timestamp if 'Last Updated' header exists, but not in the header row itself!
var cell = sheet.getRange(index, dateCol + 1);
var date = Utilities.formatDate(new Date(), timezone, timestamp_format);
cell.setValue(date);
}
}
Above is the code I am running in my sheet. Now This on edit event is supposed to grab the column title from the currently active cell. then using if statements should be putting a static value into the timestamp column name so I can put timestamps in my sheet. I am having a really hard time debugging this since I don't know how to debug on edit in the google scripting screen. So I can't tell what is not right about the code. Right now it does nothing.