Hide Sheets from a List Containing the Sheet names? - google-apps-script

I need to hide sheets from a list containing the respective name sheets.
I will have a Filter function, each time i open the file I want the Hidden sheets updated.
I have this, but this is fixed values or fixed names.. and i need to write 30 variables...
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var inicio = ss.getSheetByName("INICIO");
var lasanhavegetariana = ss.getSheetByName("LasanhaVegetariana");
var arrozdepato = ss.getSheetByName("ArrozDePato");
var bacalhau = ss.getSheetByName("Bacalhau");
var iniciocell1 = inicio.getRange('C2');
var iniciocell2 = inicio.getRange('C3');
var iniciocell3 = inicio.getRange('C4');
if (iniciocell1.getValue() == 0) {lasanhavegetariana.hideSheet();}
if (iniciocell1.getValue() == 1) {lasanhavegetariana.showSheet();}
if (iniciocell2.getValue() == 0) {arrozdepato.hideSheet();}
if (iniciocell2.getValue() == 1) {arrozdepato.showSheet();}
if (iniciocell3.getValue() == 0) {bacalhau.hideSheet();}
if (iniciocell3.getValue() == 1) {bacalhau.showSheet();}
}
How do i write a function that hide sheets from a range A1:A20??

As you mentioned, it would be better to grab the whole range and then iterate from there instead of create a new variable for each sheet.
If you have the the list of sheet names in column 'A' and the flag value in column 'B' (i know you have it in C i just change it to make it easier), you can iterate each row, get the name of the sheet and the flag value and just call the function getSheetByName and then, depending on the flag value, hideSheet or showSheet.
function hide()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var row =ss.getLastRow();
var col =ss.getLastColumn();
var range = ss.getSheetByName('INICIO').getRange(1,1,row,col).getValues();
for(var i =1; i<range.length; i++)
{
var name = range[i][0]; // get the value in column A
var flag = range[i][1]; // get the value in column B
var sheet = ss.getSheetByName(name); //It would be better to validate if the function returned a value
//so the code won't stop if it cannot find the sheet.
if(flag == 0)
{
sheet.hideSheet();
}
else
{
sheet.showSheet();
}
}
}
Make sure the names of the sheets are correct so the function can find them. Hope this helps.

You could get the data as a range and based upon those values you can hide the required sheets.
To hide sheets on the opening of the spreadsheet, use the hideSheets() in the onOpen().
This also checks the condition if you don't have those many sheets as specified by flags in the fixed data range A1:A10.
function onOpen(){
var ui = SpreadsheetApp.getUi();
ui.createMenu('Hide Sheets')
.addItem('Hide Sheets', 'hideSheets')
.addItem('Show All Sheets', 'showAllSheets')
.addToUi();
}
function hideSheets() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var configSheet = ss.getSheets()[0];
var sheetValues = configSheet.getRange('A1:A10').getValues();
Logger.log(sheetValues);
for(var i=0;i<sheetValues.length;i++){
if(ss.getSheets()[i]!=undefined){
if(sheetValues[i]==0){
ss.getSheets()[i].hideSheet();
}else{
ss.getSheets()[i].showSheet();
}
}
}
}
function showAllSheets() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
for(var i=0;i<ss.getSheets().length;i++)
ss.getSheets()[i].showSheet();
}
Demo spreadsheet with the above functionality.

Related

How to refresh a filter onEdit() in Google sheets?

I have a sheet where I fill data with Hlookups depending on the values I choose in dropdowns.
I want to filter (hide) the rows that have a NULL or blank value in column 3 each time I change the values in the dropdowns (which changes the whole dataset).
If I create a normal filter, it doesn't refresh when the data changes.
var PARAMETER_ROW_NUMBER = 5; //The parameters goes from Row 1 to this Row
var PARAMETER_COLUMN_NUMBER = 2; //The column where the dropdowns with the parameters for the VLOOKUPs are
function onEdit()
{
var thisSheet = SpreadsheetApp.getActiveSheet();
if( thisSheet.getName() == "By Place" )
{
var cell = thisSheet.getActiveCell();
var cellRow = cell.getRow();
var cellColumn = cell.getColumn();
if( cellColumn == PARAMETER_COLUMN_NUMBER && cellRow <= PARAMETER_ROW_NUMBER)
{
setFilter(); // Execute the filter to clean null rows each time I change the values in the dropdowns
var rowDiff = PARAMETER_ROW_NUMBER - cellRow;
cell.offset( 1, 0, rowDiff).setValue(''); // As the parameters are dependent dropdowns, I clear the dropdowns if one changes
}
}
}
function setFilter()
{
var ss = SpreadsheetApp.getActiveSheet();
var rang = ss.getDataRange();
var filtercriteria = SpreadsheetApp.newFilterCriteria().setHiddenValues([' ','']).build();
var filter = rang.getFilter() || rang.createFilter();
filter.setColumnFilterCriteria(3, filtercriteria); // I want to hide the rows which has a null or blank in column 3
}
The setFilter() function doesn't work.
The array you're using to set the hidden values is not correct, try your code like this:
function setFilter()
{
var ss = SpreadsheetApp.getActiveSheet();
var rang = ss.getDataRange();
var filterCriteria = SpreadsheetApp
.newFilterCriteria()
.setHiddenValues(['NULL', ''])
.build();
var filter = rang.getFilter() || rang.createFilter();
filter.setColumnFilterCriteria(3, filterCriteria);
}
Also, if you want to see the logs from your onEdit executions, you can check them on your Apps Script file by clicking in View - > Executions, there you will be able to see the errors you are getting.
Docs
I used these docs to help you:
setColumnFilterCriteria(columnPosition, filterCriteria).
Class FilterCriteriaBuilder.

Google Sheet Apps Script - Change Cell Data and Increment One Row Down

I'm trying to.. 1) replace a substring from the contents of the active cell in my sheet, and.. 2) move the active cell down one spot, and repeat until the active cell value is empty. Here's my function, but nothing happens when I run it...can anyone see why?
var app = SpreadsheetApp;
var mySheet = ss.getSheetByName('NAME');
var activeCell = mySheet.getActiveCell();
var cellValue = activeCell.getValue();
var activeRow = activeCell.getRow();
function replaceStringInCell(){
while(cellValue != ''){
var newCellValue = cellValue.replace('MC/Visa/Discover', 'CC');
activeCell.setValue(newCellValue);
activeRow++;
mySheet.getRange(activeRow, 7).activate();
}
}
Issue:
Unnecessary looping over each cell
Solution:
Use batch operations
Sample Script:
function replaceColA() {
var ss = SpreadsheetApp.getActive();
var mySheet = ss.getSheetByName('NAME');
var cellRange = mySheet.getRange('A1:A' + mySheet.getLastRow());
var cellValues = cellRange.getValues().map(replaceStringInCell); //call replace function on all values in range
cellRange.setValues(cellValues); //set mapped values back to range
}
function replaceStringInCell(cellValue) {
if (cellValue.map) {
//if cellValue is a array
return cellValue.map(replaceStringInCell); //recurse
} else {
return cellValue.replace('MC/Visa/Discover', 'CC');
}
}
To Read:
Arrays
Array#Methods
Array#2DFromSpreadsheets
Array#map
String#replace

Google Spreadsheet: run script on cell value change

In a spreadsheet I have two sheets, * and Calculator. When I change the value on "*"!B1 (i.e. cell B1 of sheet *), I want to run the script: to change (actually clear) the value of "Calculator"!B3 (i.e. cell B3 of sheet "Calculator").
Here's my code. I created it through Spreadsheet > Tools > Script editor, so it's not an standalone:
The difference between Version 1 and 2 is that in Version 1 the first function is run and the second is missed (vice versa in Version 2), plus one thing I'll detail below.
Version 1
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var languageSheet = ss.getSheetByName("*").getSheetName();
var languageCell = languageSheet.getRange("B1");
var sheets = ss.getSheets()[0];
var languageCellCheck = sheets.getActiveCell();
var cookingMethodSheet = ss.getSheetByName("Calculator").getSheetName();
var cookingMethodCell = cookingMethodSheet.getRange("B3");
var range = e.range;
if (range == languageCell)
cookingMethodCell.setValue("A");
}
//function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var languageCell = ss.getSheetByName("*").getRange("B1");
var sheets = ss.getSheets()[0];
var languageCellCheck = sheets.getActiveCell();
var cookingMethodCell = ss.getSheetByName("Calculator").getRange("B3");
var range = e.range;
if (range == languageCell)
cookingMethodCell.setValue("A");
//}
Version 2
//function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var languageSheet = ss.getSheetByName("*").getSheetName();
var languageCell = languageSheet.getRange("B1");
var sheets = ss.getSheets()[0];
var languageCellCheck = sheets.getActiveCell();
var cookingMethodSheet = ss.getSheetByName("Calculator").getSheetName();
var cookingMethodCell = cookingMethodSheet.getRange("B3");
var range = e.range;
if (range == languageCell)
cookingMethodCell.setValue("A");
//}
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var languageCell = ss.getSheetByName("*").getRange("B1");
var sheets = ss.getSheets()[0];
var languageCellCheck = sheets.getActiveCell();
var cookingMethodCell = ss.getSheetByName("Calculator").getRange("B3");
var range = e.range;
if (range == languageCell)
cookingMethodCell.setValue("A");
}
When I say "Version 1" I mean I changed the value of "*"!B1 from "Something" to "Whatever", and cell "Calculator"!B3 wasn't changed. Then, using Version 2, I tried the same but got the same result (no change in B3).
The idea of having two functions (same for both versions) is because I don't know if using ss.getSheetByName("Calculator").getSheetName(); or directly selecting in as in ss.getSheetByName("*").getRange("B1"); will make a difference. Apparently, it doesn't.
What's and where's the error?
Going by your variable name var languageSheet = ss.getSheetByName("*").getSheetName(); it seems that you expect languageSheet to actually be a sheet object and not a string. That seems to be reaffirmed var sheets = ss.getSheets()[0];
As such you must edit that line to say var languageSheet = ss.getSheetByName("*") and the same goes further on with var cookingMethodSheet = ss.getSheetByName("Calculator")
Now the real problem:
if (range == languageCell)
cookingMethodCell.setValue("A");
this will always return false. You are comparing two different objects. They will never be the same. You need to compare their column and row or A1 notation instead by using something like range.getColumn() and range.getRow() or range.getA1Notation(). Currently it's like you write the number 3 on two pieces of paper and ask if the two pieces of paper are the same thing. They will both have the same value and be comparable, but they will never be the same piece of paper.
Furthermore, going by your code, you are getting the edited range and then you get the active cell which will always be the same cell. So you might as well have the logic be if (1 == 1) or more specifically, because you are comparing to range type objects, it's like writing if (1 == 2)
EDIT: With the things considered in the comments of this answer you are making things more complicated then they need to be. Here is a function that will clear B1:B3 in Calculator only if B1 in * is changed:
function onEdit(e) {
var langName = '*'
var langCell = 'B1'
var curSheet = e.range.getSheet()
if (curSheet.getName() === langName) {
if (e.range.getA1Notation() === langCell) {
var cookingMethodSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Calculator')
var range = cookingMethodSheet.getRange('B1:B3')
range.clear()
}
}
which you can make a little shorter by doing
function onEdit(e) {
if (e.range.getSheet().getName() === '*') {
if (e.range.getA1Notation() === 'B1') {
SpreadsheetApp
.getActiveSpreadsheet()
.getSheetByName('Calculator')
.getRange('B1:B3')
.clear()
}
}
The indentation is there only so the line is not too long.

for each in ss.getSheets() get a range of data

I'm struggling on a child task within a function I'm working on.
For each sheet in sheets, I would like to get the data in range A16:D, combine into one big array and then out put the combined data into a new sheet. But each time I try to select each data range it comes as undefined?
How can I get the data from each sheet in sheets and then add into one big array?
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ranges = [];
function combineData() {
var activeSheetName = ss.getActiveSheet().getName();
var sheets = ss.getSheets();
sheets.forEach(function(e) {
var sheetName = e.getName();
if (sheetName != activeSheetName && sheetName != 'Report Configuration' && sheetName != 'Sheet1')
var wee_data = e.getRange('A16:D').getValues(); // TROUBLE HERE, WEE_DATA IS UNDEFINED
for(var j = 0; j<wee_data.length; j++) {
store.push(wee_data[j]);
}
ranges.push(wee_data);
});
if (ranges.length) {
Logger.log('range length is: ' + ranges.length);
adjustSheetLength(); // ensure there are enough rows in the destination sheet.
// figure out how to output data array "ranges" into a sheet "combined".
}
}
function adjustSheetLength(){
var comb = ss.getSheetByName('combined');
var lastRow = 4;
var maxRows = comb.getLastRow();
comb.deleteRows(lastRow, maxRows-lastRow);
var datapullSize = ranges.length;
comb.insertRows(4, datapullSize-2);// insert exactly the number of rows you need.
}
I think your issue is in the .forEach callback function. When I debugged those functions I got a not allowed in callback exception.
Change the foreach to a for in I think that'll fix your issue.
for( var i in sheets ) {
Logger.log(sheets[i]);
...
}

Creating Menu that allows to hide or unhide 2 different columns if their value is equal to 0 in Google Doc Script

I have a google doc that has formulas in column C and Column D. It's a forecasting sheet so I know what we have on hand (C) and what we have on order (D). I want a script that opens a menu at the top so I can quickly hide or unhide Column C values that are equal to 0 and the same with column D.
I've pulled this script from someone on here to create a menu for hiding rows but I can't get it to work with my application. I'm not sure if the formulas in the cells prevent the function from finding 0's or not.
UPDATE: I have the first function working. It hides all rows with a 0 in column C. When a row is hidden and is updated to have a value, the function does not unhide it though. The second function is still not unhiding all. Once I get these two figured out I can build out the same thing for Column D. Below is updated script
function onOpen() {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// create menu
var menu = [{name: "Show Only On Hand", functionName: "hideRow"},
{name: "Show All", functionName: "showRow"}];
// add to menu
ss.addMenu("Filter", menu);
}
function hideRow() {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get first sheet
var sheet = ss.getSheetByName('Inventory')
// get data
var data = sheet.getDataRange();
// get number of rows
var lastRow = data.getLastRow()+1;
Logger.log(lastRow);
// itterate through rows
for(var i=1; i<lastRow; i++) {
if(data.getCell(i, 3).getValue() == 0) {
sheet.hideRows(i);
}
}
}
function showRow() {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get first sheet
var sheet = ss.getSheets()[0];
// get data
var data = sheet.getDataRange();
// get number of rows
var lastRow = data.getLastRow();
// show all rows
sheet.showRows(lastRow, 1);
}
I won't do everything for you, cause this isn't this sites goal, but I'll point to where the script could be failing, by line:
var sheet = ss.getSheets()[0];
Is it always the first sheet you're using? If not, you can use the method getSheetByName().
for(var i=1; i<lastCol; i++) {
This iterates trough the columns, do you really want that? If it is for rows, you'll need to change the getLastColumn for a row method.
if(data.getCell(i, 3).getValue() == '0') {
Again, if it is row that you want to hide, you'll have to refactor getCell, since i is the row, and 3 is the column, you can add another conditional since you also want column D.
Also, you may need to log the data.getCell() to check if the 0 is really coming as a String, if it is coming as a number remove the single quotes.
sheet.hideColumns(i);
Again, for row, this need to be refactored.
Update:
To show all you can:
var sheet = SpreadsheetApp.getActiveSheet();
var fullSheetRange = sheet.getRange(1,1,sheet.getMaxRows(), sheet.getMaxColumns() )
sheet.unhideColumn( fullSheetRange );
sheet.unhideRow( fullSheetRange ) ;
And then hide them. To do this for column all you have to do is copy and change the column C specied in getCell(), you can add another condition in the if with the OR logical operator.
Huge thanks to Kriggs for helping me figure this one out. I'm sure it's a bit clunky, but it works perfect for what I need.
function onOpen() {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// create menu
var menu = [{name: "Show Only On Hand", functionName: "hideRow"},
{name: "Show Only On Order", functionName: "hideorder"}];
// add to menu
ss.addMenu("Filter", menu);
}
function hideRow() {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get first sheet
var sheet = ss.getSheetByName('Inventory')
// get data
var data = sheet.getDataRange();
// get number of rows
var lastRow = data.getLastRow()+1;
Logger.log(lastRow);
var sheet = SpreadsheetApp.getActiveSheet();
var fullSheetRange = sheet.getRange(1,1,sheet.getMaxRows(), sheet.getMaxColumns() )
sheet.unhideColumn( fullSheetRange );
sheet.unhideRow( fullSheetRange ) ;
// itterate through rows
for(var i=1; i<lastRow; i++) {
if(data.getCell(i, 3).getValue() == 0) {
sheet.hideRows(i);
}
}
}
function hideorder() {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get first sheet
var sheet = ss.getSheetByName('Inventory');
// get data
var data = sheet.getDataRange();
// get number of rows
var lastRow = data.getLastRow()+1;
Logger.log(lastRow);
var sheet = SpreadsheetApp.getActiveSheet();
var fullSheetRange = sheet.getRange(1,1,sheet.getMaxRows(), sheet.getMaxColumns() )
sheet.unhideColumn( fullSheetRange );
sheet.unhideRow( fullSheetRange ) ;
// itterate through rows
for(var i=1; i<lastRow; i++) {
if(data.getCell(i, 4).getValue() == 0) {
sheet.hideRows(i);
}
}
}