Google app scripts - Why is my onEdit() function taking so long? - google-apps-script

Ok so I need to select a range that is around 350 rows and 4 columns, take the values from it and on every change in my drop down I search and compare the rows and columns from selected range and I'm finding the matches in order to filter out the drop down dataValidation's. But on every drop down change function takes around 5-6 seconds to complete.
I even tried selecting only the small range and it still uses the same amount of time. Here in code example I'm taking a range of around 20 rows and it still takes 5-6 seconds to complete.
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("EAC Input");
var dataSS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Resource names");
var activeCell = ss.getActiveCell();
var column = activeCell.getColumn();
var lastRow = dataSS.getLastRow();
if(column == 1 || column == 2 || column == 3 || column == 4 && activeCell.getRow() > 5) {
var makeValue = activeCell.getValue();
if(makeValue == "" || makeValue == "WORKSTREAM:" || !isNaN(parseFloat(makeValue)) && isFinite(makeValue))
{
return;
}
var validationRange = dataSS.getRange("A36:D55").getValues();
var filteredRangeOfDepartments = [];
var filteredRangeOfPositions = [];
var filteredRangeOfEmployees = [];
for(var i = 0; i < validationRange.length; i++)
{
var rangeAtZero = validationRange[i][0];
var rangeAtOne = validationRange[i][1];
var rangeAtTwo = validationRange[i][2];
if(rangeAtZero== makeValue)
{
filteredRangeOfDepartments.push(rangeAtOne);
}
if(rangeAtOne == makeValue && rangeAtZero == activeCell.offset(0, -1).getValue())
{
filteredRangeOfPositions.push(rangeAtTwo);
}
if(rangeAtTwo == makeValue && rangeAtZero == activeCell.offset(0, -2).getValue() && rangeAtOne == activeCell.offset(0, -1).getValue())
{
filteredRangeOfEmployees.push(validationRange[i][3]);
}
}
if(column == 1)
{
var validationRule = SpreadsheetApp.newDataValidation().requireValueInList(filteredRangeOfDepartments, true).build();
activeCell.offset(0, 1).setDataValidation(validationRule);
}
if(column == 2)
{
var validationRule = SpreadsheetApp.newDataValidation().requireValueInList(filteredRangeOfPositions, true).build();
activeCell.offset(0, 1).setDataValidation(validationRule);
}
if(column == 3)
{
filteredRangeOfEmployees.push("TBC");
var validationRule = SpreadsheetApp.newDataValidation().requireValueInList(filteredRangeOfEmployees, true).build();`enter code here`
activeCell.offset(0, 1).setDataValidation(validationRule);
}
}
}

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.

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.

How can I combine the two onEdit? [duplicate]

This question already has an answer here:
Merging or Combining two onEdit trigger functions
(1 answer)
Closed 2 years ago.
I made a dependent drop-down with a script.
I'd like to apply it to two sheets.
but only OnEdit1 works and onEdit2 doesn't work.
I don't know what to do with both sheets.
Do I have to add or do something to make two sheets work?
function onEdit(e){
oneEdit1(e);
var tabLists = "lists";
var tabValidation = "Question_B";
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var datass = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(tabLists);
var activeCell = ss.getActiveCell();
if(activeCell.getColumn() == 4 && activeCell.getRow() > 1 && ss.getSheetName() == tabValidation){
activeCell.offset(0, 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(3, makeIndex, datass.getLastRow());
var validationRule = SpreadsheetApp.newDataValidation().requireValueInRange(validationRange).build();
activeCell.offset(0, 1).setDataValidation(validationRule);
}
}
oneEdit2(e);
var tabListss = "lists2";
var tabValidations = "Qeustion_R";
var sss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var datasss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(tabListss);
var activeCell = sss.getActiveCell();
if(activeCell.getColumn() == 4 && activeCell.getRow() > 1 && ss.getSheetName() == tabValidations){
activeCell.offset(0, 1).clearContent().clearDataValidations();
var makess = datasss.getRange(1, 1, 1, datasss.getLastColumn()).getValues();
var makeIndexs = makess[0].indexOf(activeCell.getValue()) + 1;
if(makeIndex != 0){
var validationRange = datasss.getRange(3, makeIndexs, datasss.getLastRow());
var validationRule = SpreadsheetApp.newDataValidation().requireValueInRange(validationRange).build();
activeCell.offset(0, 1).setDataValidation(validationRule);
}
}
}
Two combine two onEdit functions in one:
define both of them outside of the main function
call them from the main function
Sample:
function onEdit(e){
oneEdit1(e);
oneEdit2(e)
}
function oneEdit1(e){
...
}
function oneEdit2(e){
...
}

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");
}
}

How to pass a variable from an onEdit(e) function

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');
}
}
}
}