How do you show/hide rows based on a particular cell value? - google-apps-script

I am attempting to put some show/hide row logic into a google sheet based on a response from a data validation list.
If the user selects the value 'General Account Call' from the data validation list in cell C42 I would like to show rows 43 through to 53 and rows 78 through to 101. Also if a user ticks a check box in cell C40 I would like to show row C41.
I don't know if I can 'monitor' multiple cells with the onEdit function.
I have found a couple of similar(ish) scripts which hide a row based on a value in a cell in the same row and have tried amending them to no avail. I have then tried going back to basics and putting something to monitor a cell and hide a different row, again to no avail
function onEdit(e) {
var ss = SpreadsheetApp.getActive()
var sheet = SpreadsheetApp.getActiveSheet()
var cell = sheet.getRange('D39')
var cellContent = cell.getValue()
if(cellContent === Y) {
Sheet.hideRow(40)
}
}

Your code should be:
function onEdit() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var cell = sheet.getRange('D39');
var cellContent = cell.getValue();
if(cellContent == 'Y') {
sheet.hideRows(11);
}
}
There were a few things wrong:
Even if the ss and sheet declaration work, you were getting the
Sheet from the SpreadsheetApp and not from ss, so ss was not
being used.
cellContent == 'Y' is the correct way to compare the cell to a String, if you remove the quotes, it will interpret it as a variable Y that doesn't exist. Also, === is not necessary as it checks the type and the value, and we only want the value. In fact, it will return false even if the values are the same but are a different type
You wrote Sheet.hideRow instead of sheet.hiderow. Javascript is case-sensitive, so be careful with that!
The method hideRow hides the rows in a given Range, so we have to use hideRows, were you can use the integer (11 in this case) to hide the entire row.
You didn't put any semicolons ;
You didn't get any of these errors as I suppose you were testing the code changing the value of D39. If you execute the code manually, all of these will show up.
So, in order to hide several rows depending of a few cells, you have to get the event information (e), and get the cell that is being edited.
Do an if like this:
var cell = e.range.getA1Notation(); //Gets the Cell you edited
var cell_value = e.range.getValue(); //Gets the value of the cell
if(cell == 'C42' && cell_value == 'General Account Call'){
sheet.showRows(43, 10);
sheet.showRows(78, 23);
}
if (cell == 'C40' && cell_value){ //The checkbox value returns true or false
sheet.showRows(41);
}
The second number in showRows is the number of rows that will be shown.

Related

Googlesheet dropdown list to show/hide rows

I want to have various cells that have a dropdownlist to show/hide certain rows
I have the following table
If I select A2 (dropdownlist with AMERICAS_a and AMERICAS_s), with the _s option, I want to hide only rows 3 to 6
If I select A7 (dropdownlist with EUROPE_a and EUROPE_s), with the _s option, I want to hide only rows 8 to 12
I am using an Appscript which works only for 1 of the continent. I want to make it work for any of the Watchcell
function onEdit(a) {
var watchSheet = "Sheet1";
var watchCell = "A2";
var sheet = a.range.getSheet();
if (sheet.getName() !== watchSheet ||
a.range.getA1Notation() !== watchCell) {
return;
}
sheet.hideRows(2, 5);
switch (a.value) {
case "AMERICAS_a":
sheet.showRows(2, 5);
break;
case "AMERICAS_s":
sheet.showRows(2, 1);
break;
default:
}
}
But I am unsure how to add A7 as another watchcell. I have repeated the function onEdit(e) but only the last onEdit function works.
I believe your goal is as follows.
Your Spreadsheet has the data validation rules for several cells in the column "A".
When the value of the dropdown list is changed, you want to run the script.
For example, when the suffix letters of the value of the dropdown list are _s, you want to hide rows until the next dropdown list.
For example, when the suffix letters of the value of the dropdown list are _a, you want to show rows until the next dropdown list.
Modification points:
In your showing script, in the case of both values of AMERICAS_a and AMERICAS_s, the rows are shown.
From your question, I thought that when the position of data validation rules is retrieved, the script might become simple.
When these points are reflected in a sample script, it becomes as follows.
Modified script:
function onEdit(e) {
const sheetName = "Sheet1"; // Please set the sheet name.
const { range, value } = e;
const sheet = range.getSheet();
const row = range.rowStart;
const datavalidations = sheet.getRange("A1:A" + sheet.getLastRow()).getDataValidations();
if (sheet.getSheetName() != sheetName || !datavalidations[row - 1][0]) return;
datavalidations.splice(0, row);
const n = datavalidations.findIndex(([a]) => a);
sheet[value.slice(-2) == "_s" ? "hideRows" : "showRows"](row + 1, n > -1 ? n : datavalidations.length);
}
Testing:
When this script is used, the following result is obtained.
Note:
This sample script is for your sample showing Spreadsheet. So, when you change the structure of the Spreadsheet, this script might not be able to be used. Please be careful about this.
When this script is directly run with the script editor, an error like TypeError: Cannot destructure property 'range' of 'e' as it is undefined. occurs. Please be careful about this. Please change the dropdown list of the column "A".
References:
Simple Triggers
hideRows(rowIndex, numRows)
showRows(rowIndex, numRows)

I am trying to set the value of multiple cells when the value of once cell changes in google sheets

I am trying to set the values of several cells in the same row of a cell that I am changing.
IF the value in AJ2 is True then the range AK2:AX2 should also be true.If I change AJ2 to false, then I should be able to uncheck any of the values in the range and they would then be false. I 'sort of' have this logic working. IF I have AJ2 checked and uncheck AK2, when I uncheck AJ2 it rechecks AK2.
I also need this to happen on all rows if I change the value in the column of AJ for their rows. not just row 2. I am fairly new to working with sheets and could use some help.
function onEdit(e) {
var ss=SpreadsheetApp.getActiveSpreadsheet();
var cell = ss.getRange("AJ2");
var range =ss.getRange("AK2:AX2")
var activeCell = ss.getActiveCell();
if(activeCell.getColumn() == 36&&ss.getActiveSheet().getName()=="MasterData") {
if (Cell = "TRUE")
range.setValue("TRUE")}
}
Try this
function onEdit(e) {
const sheet = e.source.getActiveSheet();
const cell = e.range;
// AJ = column 36 (master column)
if(sheet.getName() == "MasterData" && cell.getColumn()==36 && cell.isChecked()){
sheet.getRange(cell.getRow(),37,1,14).setValue('TRUE')
}
// individual columns : 37 (AK) to 50 (AX)
if(sheet.getName() == "MasterData" && cell.getColumn()>=37 && cell.getColumn()<=50 && !cell.isChecked()){
sheet.getRange(cell.getRow(),36,1,1).setValue('FALSE')
}
}
explanation
when a box is checked in column 36 (AJ = 'master column'), all the boxes of the same row between 37 to 50 (AK to AX) will be checked
when an individual box is unchecked between column 37 to 50 (AK to AX) the master box of the same row will be also unchecked
reference
onEdit trigger
The onEdit(e) simple trigger returns an event object.
The event object contains the information about the spreadsheet that was edited, which you use instead of the "SpreadsheetApp.getActiveSpreadsheet()"
To access the information in the event object, you need to use the 'e':
function onEdit(e) {
//the sheet that was edited
var sheet = e.source.getActiveSheet();
//the cell that was edited
var cell = sheet.getActiveCell();
//the row number of the cell that was edited
var row = cell.getRow();
//the column number of the cell that was edited
var column = cell.getColumn();
From there, proceed as you normally would with sheets and ranges.
To update multiple cells at once, you can set the range with getRange(row, column, numRows, numColumns) and then setValues(values). Note that it's setValues(), not setValue().

Automatically hide rows based on other cell value

We have a spreadsheet that automatically attributes status for each row based on information enteredin cells located in column T. The stauts appear on column M showing open, pending and closed. I'm using the following code:
// Sheet the data is on.
var SHEET = "DLT";
// The value that will cause the row to hide.
var VALUE = "Closed"
// The column we will be using
var COLUMN_NUMBER = 14
function onEdit (e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activeSheet = ss.getActiveSheet();
//Ensure on correct sheet.
if(SHEET == activeSheet.getName()){
var cell = ss.getActiveCell()
var cellValue = cell.getValue();
//Ensure we are looking at the correct column.
if(cell.getColumn() == COLUMN_NUMBER){
//If the cell matched the value we require,hide the row.
if(cellValue == VALUE){
activeSheet.hideRow(cell);
};
};
};
}
I understand that there is a mistake on the code, as the spreadsheet changes automatically the "stauts" value on column M as soon as information is entered on column T, and this code this won't work because technically the Active.cell bit is telling the script to look at the current cell being edited (which in this case will be the cell on column T as this is the last field to be filled before triggering the spreadsheet change status to closed.)
Doubt is, how to make the script still looks into the current row being edited but consider the value on column M and not the active cell.
function onEdit (e) {
var sh = e.range.getSheet();
//column 20 is T
if(sh.getName()== 'DLT' && e.range.columnStart == 20 ){
SpreadsheetApp.flush();//This will provide enough time to allow the spreadsheet to complete all of it's calculations.
//column 13 is M
if(e.range.offset(0,-7).getValue()=="Closed") {
sh.hideRows(e.range.rowStart);
}
};
}

Googlesheet script variable triggered only with manual cell input

I am trying something reasonably simple but can’t get it to work:
I want to hide multiple columns and/or rows based on the value of a cell.
I have it working with a simple script however it seems to only do its job when the trigger cell in question has the value input manually, i.e. I have a drop-down list of “0” & “1” and when I change it manually from “0” to “1” it all works.
However, the cell in question gets its value itself from a simple if condition and even though the value is, in the end, the same it seems the script is not working in such a case.
I would be grateful for any help.
That's the script I found online and is apart from not being triggered correctly in my case very useful:
//TITLE:
//Hide a row if a value is inputted.
//**GLOBALS**
// Sheet the data is on.
var SHEET = "TEST2";
// The value that will cause the row to hide.
var VALUE = "1";
// The column we will be using
var COLUMN_NUMBER = 1
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activeSheet = ss.getActiveSheet();
//Ensure on correct sheet.
if(SHEET == activeSheet.getName()){
var cell = ss.getActiveCell()
var cellValue = cell.getValue();
//Ensure we are looking at the correct column.
if(cell.getColumn() == COLUMN_NUMBER){
//If the cell matched the value we require,hide the row.
if(cellValue == VALUE){
activeSheet.hideRow(cell);
};
};
};
}
The cell(s) in question use this simple line:
=IF(INDIRECT("A4")=1,"0",IF(E10="NON-FACS",1,0))
Current outcome is: Nothing happens (except when input manually)
The expected outcome is: column number 1 should be hidden

Google Sheets move cursor onEdit trigger based on cell content

I am trying to write a Google Sheets Apps Script function that checks the content of the current active cell, matches it to the content of another cell, then moves the cursor according to the result of that check.
For a spreadsheet as this example one:
https://docs.google.com/spreadsheets/d/1kpuVT1ZkK0iOSy_nGNPxvXPTFJrX-0JgNmEev6U--5c/edit#gid=0
I would like the user to go to D2, enter a value followed by Tab, then while the active cell is in E2, the function will check if the value in D2 is the same in B2. If it is, stays in E2.
Then we enter the value in E2 followed by Tab, the function checks if it's the same as C2, if it is, then moves from F2 down and left twice to D3. So if all the values are entered correctly, the cursor zig-zags between the cells in D, E and F as shown below:
The closest I could find is the answer to the one below, but it involves clicking on a method in the menu each time:
Move sheet rows on based on their value in a given column
I imagine the function could be triggered at the beginning of editing the document, then it keeps moving the cursor until the document is completed, at which point the function can be stopped.
Any ideas?
EDIT: what I've tried so far:
I have managed to change the position to a hard-coded position 'D3' and to create a function that moves one down with these functions:
function onOpen() {
var m = SpreadsheetApp.getUi().createMenu('Move');
m.addItem('Move to D3', 'move').addToUi();
m.addItem('Move to one below', 'move2').addToUi();
m.addItem('Move down left', 'move_down_left').addToUi();
}
function move() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
var range = s.getRange('D3');
s.setActiveRange(range);
}
function move2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
var r = s.getActiveRange();
var c = r.getCell(1,1);
var target = s.getRange(c.getRow() + 1, c.getColumn());
s.setActiveRange(target);
}
function move_down_left() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
var r = s.getActiveRange();
var c0 = r.getCell(1,1);
var r1 = s.getRange(c0.getRow(), c0.getColumn() - 1);
var c1 = r1.getCell(1,1);
var r2 = s.getRange(c1.getRow(), c1.getColumn() - 2);
var c2 = r2.getCell(1,1);
if (c1.getValue() == c2.getValue()) {
var target = s.getRange(c1.getRow() + 1, c1.getColumn() - 1);
s.setActiveRange(target);
}
}
As I mentioned in my comment, you want to use a simple trigger function (so that it works for all users without requiring them to first authorize the script). There are naturally some limitations of simple triggers, but for the workflow you describe, they do not apply.
A key principle of a function receiving the on edit trigger invocation is that it has an event object with data about the cell(s) that were edited:
authMode:
A value from the ScriptApp.AuthMode enum.
oldValue:
Cell value prior to the edit, if any. Only available if the edited range is a single cell. Will be undefined if the cell had no previous content.
range:
A Range object, representing the cell or range of cells that were edited.
source:
A Spreadsheet object, representing the Google Sheets file to which the script is bound.
triggerUid:
ID of trigger that produced this event (installable triggers only).
user:
A User object, representing the active user, if available (depending on a complex set of security restrictions).
value:
New cell value after the edit. Only available if the edited range is a single cell.
Of these, we will use range and value. I will leave the business case of handling edits to multiple-cell ranges to you. Stack Overflow is, after all, not where you obtain turnkey solutions ;)
function onEdit(e) {
if (!e) throw new Error("You ran this from the script editor");
const edited = e.range;
if (edited.getNumRows() > 1 || edited.getNumColumns() > 1)
return; // multicell edit logic not included.
const sheet = edited.getSheet();
if (sheet.getName() !== "your workflow sheet name")
return;
// If the user edited a specific column, check if the value matches that
// in a different, specific column.
const col = edited.getColumn(),
advanceRightColumn = 5,
rightwardsCheckColumn = 2;
if (col === advanceRightColumn) {
var checkedValue = edited.offset(0, rightwardsCheckColumn - col, 1, 1).getValue();
if (checkedValue == e.value) // Strict equality may fail for numbers due to float vs int
edited.offset(0, 1, 1, 1).activate();
else
edited.activate();
return;
}
const endOfEntryColumn = 8,
endCheckColumn = 3,
startOfEntryColumn = 4;
if (col === endOfEntryColumn) {
var checkedValue = edited.offset(0, endCheckColumn - col, 1, 1).getValue();
if (checkedValue == e.value)
edited.offset(1, startOfEntryColumn - col, 1, 1).activate();
else
edited.activate();
return;
}
}
As you digest the above, you'll note that you are required to supply certain values that are particular to your own workflow, such as a sheet name, and the proper columns. The above can be modified in a fairly straightforward manner to advance rightward if the edited column is one of several columns, using either a constant offset to the respective "check" column, or an array of respectively-ordered offsets / target columns. (Such a modification would almost certainly require the use of Array#indexOf.)
A caveat I note is that strict equality === fails if your edits are numbers representable as integers, because Google Sheets will store the number as a float. Strict equality precludes type conversion by definition, and no int can ever be the exact same as a float. Thus, the generic equality == is used. The above code will not equate a blank check cell and the result of deleting content.
Method references:
Range#offset
Range#activate