Get onEdit to trigger from a single cell change - google-apps-script

I am trying to run a Google App script that unhides columns, and then rehides columns based whether the cell reference says Blank or not. This is determined by a drop down in a single cell. I got the script to run fine (if a little clunky) whenever any edit is made, but when I try to add the specification of cell it flags an error with the range.
I'm very new to this so I'm a bit out of my depth so any help is appreciated!
function onEdit(e) {
if (e.range.getA1Notation() === 'B2') {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActive().getSheetByName("Group M0 loot");
sheet.showColumns(9, 35);
var range = sheet.getRange("4:4");
var num_cols = range.getNumColumns();
for (var i = 9; i <= num_cols; i++) {
var value = sheet.getRange(4,i).getValue();
if (value == "Blank") {
sheet.hideColumns(i);
};
}
}
}

Try this:
function onEdit(e) {
const sh = e.range.getSheet();
if (sh.getName() == "Group M0 loot" && e.range.columnStart == 2 && e.range.rowStart == 2) {
sh.showColumns(9, 35);
sh.getRange(4,1,1,sh.getLastColumn()).getValues().flat().forEach((c,i) => {
if(!c) {
sh.hideColumns(i + 1);
}
});
}
}

Related

Running a script by checking a checkbox on two different sheets

I'm having odd behavior on my code.
I need the script to trigger when I'm using an Ipad or a mobile phone.
I was able to have it work on one sheet "Existing client". Now I'm trying to have a second sheet "new client" that also has the same behavior but triggers others functions.
The thing is it looks like when I switch between sheets, the checkbox needs to be checked multiple times and does not trigger all the time. My solution would be to simply make another spreadsheet for the second sheet "new client" but I would still like to understand what is wrong with what I did?
Here is the code:
So I reduce the code to a minimum, meaning if i check the box, I have the time stamp in a cell. If I have two sheets, it is not working.
Thanks for your help,
j.
function onEditTriggerClientExistant() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Client existant");
var range = sheet.getActiveRange()
if (range.isChecked()) {
if (range.getA1Notation() == "B4") {
sheet.getRange('C4').setValue(new Date());
range.uncheck();
} else {
range.uncheck()
}
}
}
function onEditTriggerNouveauClient() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Nouveau Client");
var range = sheet.getActiveRange()
if (range.isChecked()) {
if (range.getA1Notation() == "A4") {
sheet.getRange('B4').setValue(new Date());
range.uncheck();
} else {
range.uncheck()
}
}
}
var ss = SpreadsheetApp.getActiveSpreadsheet()
function onEdit(e) {
let oldValue = e.oldValue;
let newValue = e.value;
var r = e.range.getRow()
var c = e.range.getColumn()
var active_sheet = ss.getActiveSheet()
var sheetName = active_sheet.getName();
if(sheetName=="sheet1" && r==4 && c==2){
}
else if(sheetName=="sheet2" && r==4 && c==1){
}
}

Where Column Y Is Empty Fill In The Value From Column X

I'm new at this so thank you for your help and your patience.
Example: I have a shared spreadsheet with a protected range 'Y:Y' where colleagues update line items. One line item we want to flag when they change it is in column 'X:X'.
My desire is to set up a trigger that runs every 24 hours and it copies the values in column 'X:X' and pastes them into empty or blank values in column 'Y:Y'.
Then a simple DAX formula would compare X to Y. This would simplify a script I'm currently using that runs every time there's an edit.
function OnEdit() {
var s = SpreadsheetApp.getActiveSheet();
if( s.getName() == "PTL" ) { //checks that we're on PTL or not
if( s.getActiveCell().getColumn() == 7 ) { //checks that the cell being edited is in column G
var modify = s.getActiveCell().offset(0, 7);
modify.setValue(new Date());
var baseline = s.getActiveCell().offset(0, 6);
if( baseline.getValue() === '' ) //checks if the adjacent cell is empty or not?
baseline.setValue(new Date());
}
}
}
Try it this way:
function OnEdit(e) {
var sh = e.range.getSheet();
if (sh.getName() == "PTL" && e.range.columnStart == 7) {
e.range.offset(0,7).setValue(new Date());
if (e.range.offset(0, 6).getValue() == '')
e.range.offset(0,6).setValue(new Date());
}
}
function notsurewhatyouwant() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('PTL');
const xy = sh.getRange(1, 24, sh.getLastRow(), 2).getValues();
xy.forEach((r, i) => {
if (r[1] == null) {
sh.getRange(i+1,25).setValue(r[0]);
}
});
}
function createTrigger() {
if(ScriptApp.getProjectTriggers().filter(t => t.getHandlerFunction() == "notsurewhatyouwant").length == 0) {
ScriptApp.newTrigger('notsurewhatyouwant').timeBased().everyDays(1).atHour(0).create();
}
}

adding timestamp on three google sheets onedit with Google Apps Script

I am adding timestamp in col a if colb is edited on 3 sheets.
I have the trigger working onEdit and the information will be updated automatically. It works fine for one, but for 3 im getting an error and cannot run the script.
Is there a simpler way to look for edit in column b in three sheets than what I am doing?
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
if (s.getName() == "Igualdad Op Hom Mu") {
var r = s.getActiveCell();
if (r.getColumn() == 2) {
var nextCell = r.offset(0, -1);
if (nextCell.getValue() === '')
nextCell.setValue(new Date());
var s2 = SpreadsheetApp.getActiveSheet();
if (s2.getName() == "Incl Per Disc") {
var r2 = s2.getActiveCell();
if (r2.getColumn() == 2) {
var nextCell2 = r2.offset(0, -1);
if (nextCell2.getValue() === '')
nextCell2.setValue(new Date());
var s3 = SpreadsheetApp.getActiveSheet();
if (s3.getName() == "Empr y Col") {
var r3 = s3.getActiveCell();
if (r3.getColumn() == 2) {
var nextCell3 = r3.offset(0, -1);
if (nextCell3.getValue() === '')
nextCell3.setValue(new Date());
}
}
}
}
}
}
}
Try this:
function onEdit(e) {
const sh=e.range.getSheet();
const shts=['Igualdad Op Hom Mu','Incl Per Disc','Empr y Col']
if( shts.indexOf(sh.getName())!=-1 && e.range.columnStart==2) {
const ts=Utilities.formatDate(new Date,Session.getScriptTimeZone(),"yyyy/MM/dd HH:mm:ss");//time stamp
const rg=e.range.offset(0,-1);//next cell to the left
if(rg.getValue()=='') {
rg.setValue(ts);
}
}
}
This function requires the onedit trigger event object so you cannot run this script from the script editor unless you supply the event object.

Google Script for Conditional Formatting w/ multiple ranges and more than one condition

Sample of the page I am usingI use a conditional format across my sheets but want to change it to Google Script instead.
For every check out date that does not have a Y, highlight yellow.
I managed to modify a script to highlight a cell based on two conditions for A:D but cannot figure out how to extend it to the other ranges in my sheet.
Here is what I have so far that I found :
function onEdit(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange("A:D");
var values = range.getValues();
//for each row that data is present
for(var i = 0; i < values.length; i++) {
var cell = sheet.getRange(i + 1, 4);
if(values[i][1] !== "") {
if(values[i][3] === "") {
cell.setBackground('yellow');
} else {
cell.setBackground(null);
}
} else {
cell.setBackground(null);
}
}
}
Links: Google App Script - Conditional Formatting Based on Another Cell
Try this:
function onEdit(e) {
//e.source.toast('Entry');
var sh=e.range.getSheet();
if(sh.getName()=="Sheet2") {
//e.source.toast('Conditional');
var vs=sh.getRange(1,1,sh.getLastRow(),4).getValues();
vs.forEach(function(r,i){
let rg=sh.getRange(i+1,4);
if(r[1]=="") {
if(r[3]=="") {
//e.source.toast('yellow');
rg.setBackground('#ffff00');
}else{
//e.source.toast('white');
rg.setBackground('#ffffff');
}
}else{
//e.source.toast('r[1] not null');
rg.setBackground('#ffffff');
}
});
}
}
I tested this a little and it seems to work
function onEdit(e) {
//e.source.toast('Entry');
var sh=e.range.getSheet();
if(sh.getName()=="Sheet2") {
//e.source.toast('Conditional');
var v=sh.getRange(6,1,sh.getLastRow()-5,sh.getLastColumn()).getValues();
var r0=sh.getRange(6,4,sh.getLastRow()-5,1);
var c0=r0.getBackgrounds();
var r1=sh.getRange(6,9,sh.getLastRow()-5,1);
var c1=r1.getBackgrounds();
var r2=sh.getRange(6,14,sh.getLastRow()-5,1);
var c2=r2.getBackgrounds();
var r3=sh.getRange(6,19,sh.getLastRow()-5,1);
var c3=r3.getBackgrounds();
var r4=sh.getRange(6,24,sh.getLastRow()-5,1);
var c4=r4.getBackgrounds();
v.forEach(function(r,i){
c0[i][0]=(r[1]=="" && r[3]=="")?'#ffff00':'#ffffff';
c1[i][0]=(r[6]=="" && r[8]=="")?'#ffff00':'#ffffff';
c2[i][0]=(r[11]=="" && r[13]=="")?'#ffff00':'#ffffff';
c3[i][0]=(r[16]=="" && r[18]=="")?'#ffff00':'#ffffff';
c4[i][0]=(r[21]=="" && r[23]=="")?'#ffff00':'#ffffff';
});
r0.setBackgrounds(c0);
r1.setBackgrounds(c1);
r2.setBackgrounds(c2);
r3.setBackgrounds(c3);
r4.setBackgrounds(c4);
}
}
Try this for the entire spreadsheet:
function onEdit(e) {
//e.source.toast('Entry');
var sh=e.range.getSheet();
//e.source.toast('Conditional');
var v=sh.getRange(6,1,sh.getLastRow()-5,sh.getLastColumn()).getValues();
var r0=sh.getRange(6,4,sh.getLastRow()-5,1);
var c0=r0.getBackgrounds();
var r1=sh.getRange(6,9,sh.getLastRow()-5,1);
var c1=r1.getBackgrounds();
var r2=sh.getRange(6,14,sh.getLastRow()-5,1);
var c2=r2.getBackgrounds();
var r3=sh.getRange(6,19,sh.getLastRow()-5,1);
var c3=r3.getBackgrounds();
var r4=sh.getRange(6,24,sh.getLastRow()-5,1);
var c4=r4.getBackgrounds();
v.forEach(function(r,i){
c0[i][0]=(r[1]=="" && r[3]=="")?'#ffff00':'#ffffff';
c1[i][0]=(r[6]=="" && r[8]=="")?'#ffff00':'#ffffff';
c2[i][0]=(r[11]=="" && r[13]=="")?'#ffff00':'#ffffff';
c3[i][0]=(r[16]=="" && r[18]=="")?'#ffff00':'#ffffff';
c4[i][0]=(r[21]=="" && r[23]=="")?'#ffff00':'#ffffff';
});
r0.setBackgrounds(c0);
r1.setBackgrounds(c1);
r2.setBackgrounds(c2);
r3.setBackgrounds(c3);
r4.setBackgrounds(c4);
}
Keep in mind if you have multiple people editing the sheet then you are going to be missing some edits because the script will not be able to keep up.

How to show/hide rows in Google Sheet depending on whether check box is ticked

I'm trying to write the appscript to hide rows depending on whether a checkbox in a certain cell is checked.
I basically have 4 different checkboxes on one tab in cells D35, E35, F35, G35. I then have 4 different sections of questions on the second tab. Depending on which box/boxes are checked on the first tab I want to show/hide different row numbers on the second tab.
I've been following different scripts online and came up with the below but it isn't working.
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var activeSheet = spreadsheet.getActiveSheet();
var inSheet = spreadsheet.getSheetByName('2');
var outSheet = spreadsheet.getSheetByName('3');
var a = inSheet.getRange('D35').getValue();
var b = inSheet.getRange('E36').getValue();
var c = inSheet.getRange('E37').getValue();
var d = inSheet.getRange('E38').getValue();
if(inSheet == activeSheet){
var cell = spreadsheet.getActiveCell()
var acell = cell.getValue();
if(acell == a){
if(acell.toString() == TRUE){
outSheet.hideRows(25,3)
}
}
if(acell == b){
if(acell.toString() == TRUE){
outSheet.hideRows(32,3)
}
}
if(acell == c){
if(acell.toString() == TRUE){
outSheet.hideRows(39,3)
}
}
if(acell == d){
if(acell.toString() == TRUE){
outSheet.hideRows(46,3)
}
}
}}
You have 4 checkboxes in one sheet (I'll call it Origin), in cells D35, E35, F35, G35.
You have 4 groups of rows in another sheet (I'll call it Destination), which are 25-27, 32-34, 39-41, 46-48.
You want to hide/show a group of rows every time a checkbox is checked/unchecked.
An onEdit trigger can be used to accomplish all this. It would check whether the edited cell is one of the checkboxes, and if that's the case, it will hide/show the corresponding group of rows. So it checks (1) which sheet is edited, (2) which row is edited and (3) which column is edited.
Then, the code would check which specific checkbox was edited and hide/show the corresponding group of rows.
So, the code could be something on the following lines:
function onEdit(e) {
var ss = e.source;
var range = e.range;
var editedSheet = e.source.getActiveSheet();
var originSheetName = "Origin";
var destSheet = e.source.getSheetByName("Destination");
var editedRow = range.getRow();
var editedCol = range.getColumn();
if (editedSheet.getName() == originSheetName && editedRow == 35 && editedCol > 3 && editedCol < 8) {
var checkbox = range.getValue();
if (editedCol == 4) {
if (checkbox) {
destSheet.hideRows(25, 3);
} else {
destSheet.showRows(25, 3);
}
}
if (editedCol == 5) {
if (checkbox) {
destSheet.hideRows(32, 3);
} else {
destSheet.showRows(32, 3);
}
}
if (editedCol == 6) {
if (checkbox) {
destSheet.hideRows(39, 3);
} else {
destSheet.showRows(39, 3);
}
}
if (editedCol == 7) {
if (checkbox) {
destSheet.hideRows(46, 3);
} else {
destSheet.showRows(46, 3);
}
}
}
}
Now, this code has a fair amount of repetition, because it repeats the process for each of the 4 checkboxes. This could be improved and the code could be minimized significantly if the indexes of the different rows to hide/show followed a certain pattern. Fortunately, it looks like these rows do follow a certain pattern: each group of rows consists of 3 rows and there is a difference between each group and the next.
So, a shorter and more efficient alternative would be the following:
function onEdit(e) {
var ss = e.source;
var range = e.range;
var editedSheet = e.source.getActiveSheet();
var originSheetName = "Origin";
var destSheet = e.source.getSheetByName("Destination");
var editedRow = range.getRow();
var editedCol = range.getColumn();
if (editedSheet.getName() == originSheetName && editedRow == 35 && editedCol > 3 && editedCol < 8) {
var checkbox = range.getValue();
var index = 7 * (editedCol - 4) + 25;
if (checkbox) {
destSheet.hideRows(index, 3);
} else {
destSheet.showRows(index, 3);
}
}
}
In this line, the index of the first row to hide/show is calculated based on the index of the edited column, so there is no need to repeat the process for all checkboxes:
var index = 7 * (editedCol - 4) + 25;
Bear in mind that I called the sheets Origin and Destination. Please change these according to your preferences.
I hope this is of any help.