How to pass a variable from an onEdit(e) function - google-apps-script

I have two scripts that run individually, but I can't seem to merge them together correctly. I am attempting to use the onEdit(e) function to capture the row of the cell that is edited, then used that row number to amend a different sheet.
function onEdit(e) {
if (
e.source.getSheetName() == "GPS" &&
e.range.columnStart == 10 &&
e.range.columnEnd == 10 &&
e.range.rowStart >= 4 &&
e.range.rowEnd <= 5000
) {
var range = e.range;
var row = range.getRow();
var change = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var url = change.getRange(row,1,1,1).getValue(); //How to use this variable????????????
function toMaster(change,row){
var dest = SpreadsheetApp.openById('destinationsheetidxxxx')
var s = dest.getSheetByName('GPS')
var data = s.getDataRange().getValues();
var url = change.getRange(row,1,1,1).getValue()
for(var i = 0; i<data.length;i++){
if(data[i][0] == url){
Logger.log((i+1))
var range = s.getRange(i+1,10,1,1);
range.setValue('Yes')
}

Try this:
function onEdit(e) {
var sh=e.range.getSheet();
if(sh.getName()=="GPS" && e.range.columnStart==10 && e.range.columnEnd == 10 && e.range.rowStart >= 4 && e.range.rowEnd<=5000) {
var row = e.range.rowStart;
var url = sh.getRange(row,1).getValue();
var dss=SpreadsheetApp.openById('destId')
var dsh=dss.getSheetByName('GPS')
var drg=dsh.getRange(row,1)
var data=drg.getValues()
for(var i = 0; i<data.length;i++){
if(data[i][0]==url){
Logger.log(i+1);
var range = dsh.getRange(i+1,10).setValue('Yes');
}
}
}
}

Related

Different trigger in a sheet for multiple IF ELSE Statement

here's my activesheet is "_input"
range F12:F21 checkboxes when it false then using default formula, when true then input normal number in offset(0,1) which is column G12:G21
range G24 is dropdown which will update offset(0,1) value, H24, when update.
here's my code
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('_input');
var range = sheet.getActiveCell();
var def = 6; // column A = 1, B = 2, etc.
var opt = false;
var row = 11;
if (range.getColumn() == def && range.getValue() == opt && range.getRow()> row && range.getRow()< 22) {
range.offset(0, 1).setValue('=IFERROR(VLOOKUP(inpItem,mstItem,2,0),0)');
}
}
function onEdit(evt) {
var sh = evt.source.getActiveSheet();
var rng = evt.source.getActiveRange("");
var tBat = rng.offset(0,1);
if (sh.getName() == '_input' && rng.getColumn() == 7 && rng.getRow() > 23 && rng.getValue() == "B1") {
tBat.setValue('09:00');
} else if (sh.getName() == '_input' && rng.getColumn() == 7 && rng.getRow() > 23 && rng.getValue() == "B2") {
tBat.setValue('15:00');
} else {
tBat.clearContent();
tBat.setNumberFormat("HH:mm");
}
}
but it doesn't work properly because when i change one of onEdit function to make another onEdit function running.
please advise for my mistake here.
When i change F12:F21 and run script to edit G12:G21 won't effect to G24 and H24.

How do I define an IF statement for a cell contains a specific value in Apps Script?

I have a script that adds a timestamp to a cell when another cell in the row is initially filled in. What I would like to do is only timestamp when a cell contains the word "Completed". It doesn't seem to be working though.
var SHEET_NAME = 'Sheet 1';
var DATETIME_HEADER = 'datetime';
function getDatetimeCol(){
var headers = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME).getDataRange().getValues().shift();
var colindex = headers.indexOf(DATETIME_HEADER);
return colindex+1;
}
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSheet();
var cell = ss.getActiveCell();
var datecell = ss.getRange(cell.getRowIndex(), getDatetimeCol());
//Here's the line where I added an "if the active cell is labelled completed then add a timestamp to the datetime column"
if (ss.getName() == SHEET_NAME && cell.getColumn() == 8 && !cell.isBlank() && datecell.isBlank() && cell.getValues == "Completed") {
datecell.setValue(new Date()).setNumberFormat("yyyy-MM-dd hh:mm");
}
}
;
Try it this way:
function onEdit(e) {
const sh = e.range.getSheet();
const col = sh.getRange(1,1,1,sh.getLastColumn()).getValues().flat().reduce((a,h,i)=> (a[h]=i+1,a),{});
const dateCell = sh.getRange(e.range.rowStart,col['datetime']);
if (sh.getName() == "SHEET_NAME" && e.range.columnStart == 8 && datecell.isBlank() && e.value == "Completed") {
datecell.setValue(new Date()).setNumberFormat("yyyy-MM-dd hh:mm");
}
}

Applying google script to all sheets except specific

I am very new to google script trying to resolve key issues in business flow.
Through search have come up with the below script for multi-level data validation for sheet Template.
How can I edit this script to run for all Sheets except specific ones (ex. Sheet1, Sheet 2)
I have found the option of excluding sheets with the code below, but not sure how to use it and where to input it
var excludes = [];
// if (excludes.indexOf(s.getName()) != -1) return;
Thanks you in advance
var mainwsMaster = "Template";
var MenuWSname = "Master Menu"
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(mainwsMaster);
var wsMenu = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(MenuWSname);
var Menu = wsMenu.getRange(2,1,wsMenu.getLastRow()-1,3).getValues();
var firstColumn = 8;
var secondColumn = 9;
var thirdColumn = 10;
function onEdit(e){
var activeCell = e.range;
var val = activeCell.getValue();
var r = activeCell.getRow();
var c = activeCell.getColumn();
var wsName = activeCell.getSheet().getName();
if(wsName === mainwsMaster && c === firstColumn && r > 6){
applyFirstLevelValidation(val,r)
} else if(wsName === mainwsMaster && c === secondColumn && r > 6){
applySecondLevelValidation(val,r);
}
}//end onEdit
function applyFirstLevelValidation(val,r){
if(val === ""){
ws.getRange(r,secondColumn).clearContent();
ws.getRange(r,secondColumn).clearDataValidations();
ws.getRange(r,thirdColumn).clearContent();
ws.getRange(r,thirdColumn).clearDataValidations();
} else {
ws.getRange(r,secondColumn).clearContent();
ws.getRange(r,secondColumn).clearDataValidations();
ws.getRange(r,thirdColumn).clearContent();
ws.getRange(r,thirdColumn).clearDataValidations();
var filteredOptions = Menu.filter(function(o){return o[0] === val });
var filteredpiata = filteredOptions.map(function(o){return o[1] } );
var cell = ws.getRange(r,secondColumn);
applyValidationToCell(filteredpiata,cell);
}
}
function applySecondLevelValidation(val,r){
if(val === ""){
ws.getRange(r,thirdColumn).clearContent();
ws.getRange(r,thirdColumn).clearDataValidations();
} else {
ws.getRange(r,thirdColumn).clearContent();
var firstLevelColValue = ws.getRange(r, firstColumn).getValue();
var filteredOptions = Menu.filter(function(o){return o[0] === firstLevelColValue && o[1] === val });
var filteredpiata = filteredOptions.map(function(o){return o[2] } );
var cell = ws.getRange(r,thirdColumn);
applyValidationToCell(filteredpiata,cell);
}
}
function applyValidationToCell(list,cell){
var rule = SpreadsheetApp
.newDataValidation()
.requireValueInList(list)
.setAllowInvalid(false)
.build();
cell.setDataValidation(rule);
}
You mentioned this code:
var excludes = [];
// if (excludes.indexOf(s.getName()) != -1) return;
for your code it would look like this instead:
var excludes = ["Sheet1","Sheet2","OtherSheetToExclude","ETC"];
if (excludes.indexOf(wsName) != -1) {return};
You would place those two lines just after the wsName variable is declared in your onEdit(e) script.
It's basically saying. "Take the name of the sheet you've just edited and look for it in this list i just made called "Excludes". If you find it in there, STOP running this function."
Try
var excludes = ['Sheet1','Sheet2'];
and then, change as following
if( excludes.indexOf(wsName) == -1 && c === firstColumn && r > 6)
for instance, focused on the onEdit function
var firstColumn = 8;
var secondColumn = 9;
var excludes = ['Sheet1','Sheet2'];
function onEdit(e){
var activeCell = e.range;
var val = activeCell.getValue();
var r = activeCell.getRow();
var c = activeCell.getColumn();
var wsName = activeCell.getSheet().getName();
if(excludes.indexOf(wsName) == -1 && c === firstColumn && r > 6){
activeCell.getSheet().getRange('A1').setValue('cas1')
} else if(excludes.indexOf(wsName) == -1 && c === secondColumn && r > 6){
activeCell.getSheet().getRange('A1').setValue('cas2')
}
}//end onEdit

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.

Google Scripts - Compare Color & Change Font Color

I am trying to compare data from two different columns and when they don't match I want the data in column 6 to turn Red and if it is changed back to match it turns back to black.
I don't want to use to conditional formating from the menue because I dont want people to be able to turn it off.
function onEdit(e) {
var sheet = e.source.getActiveSheet();
var activeCell = sheet.getActiveCell();
var col = activeCell.getColumn();
var row = activeCell.getRow();
var col6 = activeCell.getColumn( col == 6 && row >=5 && row <=55 && sheet);
var col14 = activeCell.getColumn( col == 14 && row >=5 && row <=55 && sheet);
var first = get.Value(col6);
var second = get.Value(col14);
//Start Time Function
if (col == 1 && row>=5 && row<=55 && sheet.getRange(row,col).getValue() == ""){
sheet.getRange(row,1,1,sheet.getMaxColumns()).clearContent();
}
else if (col == 1){
sheet.getRange(row,col+11).setValue(new Date()).setNumberFormat('hh:mm:ss');
sheet.getRange(row,col+13).setValue(new Date()).setNumberFormat('hhmm');
sheet.getRange(row,col+5).setValue(new Date()).setNumberFormat('hhmm');
sheet.getRange(row,col+3).setValue(new Date()).setNumberFormat();
}
//End Time Function
if (col == 8 && row>=5 && row<=55 && sheet.getRange(row,col).getValue() == ""){
sheet.getRange(row,7,1).clearContent() && sheet.getRange(row,13,1).clearContent() && sheet.getRange(row,15,1).clearContent();
}
else if (col == 8) {
sheet.getRange(row,col+5).setValue(new Date()).setNumberFormat('hh:mm:ss');
sheet.getRange(row,col+7).setValue(new Date()).setNumberFormat('hhmm');
sheet.getRange(row,col-1).setValue(new Date()).setNumberFormat('hhmm');
}
// Data Valadation Start Time
// Confirm data in column 6 matches column 14, if different set column 6 font to red.
if(first != second){
var cell = sheet.getRange(first);
cell.setFontColor("red");
}
else if(first == second){
var cell = sheet.sheet.getRange(first);
cell.setFontColor("black");
}
}
Working Code.
function onEdit(e) {
var sheet = e.source.getActiveSheet();
var activeCell = sheet.getActiveCell();
var col = activeCell.getColumn();
var row = activeCell.getRow();
//Start Time Function
if (col == 1 && row>=5 && row<=55 && sheet.getRange(row,col).getValue() == ""){
sheet.getRange(row,1,1,sheet.getMaxColumns()).clearContent();
}
else if (col == 1){
sheet.getRange(row,12,1).setValue(new Date()).setNumberFormat('hh:mm:ss'); //real time
sheet.getRange(row,14,1).setValue(new Date()).setNumberFormat('hhmm').setNumberFormat("#");
sheet.getRange(row,6,1).setValue(new Date()).setNumberFormat('hhmm').setNumberFormat("#");
sheet.getRange(row,4,1).setValue(new Date()).setNumberFormat(); //Date Row
} // END - Start Time Function
//End Time Function
if (col == 8 && row>=5 && row<=55 && sheet.getRange(row,col).getValue() == ""){
sheet.getRange(row,7,1).clearContent() && sheet.getRange(row,13,1).clearContent() && sheet.getRange(row,15,1).clearContent();
}
else if (col == 8) {
sheet.getRange(row,13,1).setValue(new Date()).setNumberFormat('hh:mm:ss'); // real time
sheet.getRange(row,15,1).setValue(new Date()).setNumberFormat('hhmm').setNumberFormat("#");
sheet.getRange(row,7,1).setValue(new Date()).setNumberFormat('hhmm').setNumberFormat("#");
} // END - End Time Function
// Data Valadation - Start Time
var firstF = sheet.getRange(row,6,1);
var secondN = sheet.getRange(row,14,1);
if(firstF.getValue() != secondN.getValue()){
var cell = firstF;
cell.setFontColor("red");
}
else {
var cell = firstF;
cell.setFontColor("black");
} // END - Data Valadation - Start Time
// Data Valadation - End Time
var firstG = sheet.getRange(row,7,1);
var secondO = sheet.getRange(row,15,1);
if(firstG.getValue() != secondO.getValue()){
var cell = firstG;
cell.setFontColor("red");
}
else {
var cell = firstG;
cell.setFontColor("black");
} // END - Data Valadation - End Time
} // END - function onEdit
Be careful not to mix up ranges and values
Also, you seem to use methods methods that do not exist in Apps Script / cannot be used with parameters
Please check the documentation for getValues() and getColumn()
A modified working sample based on your code:
function onEdit(e) {
var activeCell = e.range;
var sheet = e.range.getSheet();
var col = activeCell.getColumn();
var row = activeCell.getRow();
var first = sheet.getRange(row, 6);
var second = sheet.getRange(row, 14);
if(first.getValue() != second.getValue()){
var cell = first;
cell.setFontColor("red");
}
else {
var cell = first;
cell.setFontColor("black");
}
}