Hide rows based on checkbox and cell value in specific column

Viewed 41

How to write function onEdit which hide rows with empty cells from specific column when checkbox in this header column is unchecked? I tryed merge some codes from another questions, but I'm too weak to do this. Screen and example below

  • if I would check only checkbox H1 it should show only rows with not empty cell in H column, so it would be: 4-5 & 17-25 rows
  • if I would check only K1 checkbox it should show only rows 17-24, the rest should be hidden
  • e.t.c.

Maybe simplier - this is product list and them color variation. Checkbox should show products "on stock" with specific checked color.

google sheet checkbox

2 Answers

Use Sheet.showRows() and Sheet.hideRows() in your onEdit(e) function, like this:

/**
* Simple trigger that runs each time the user edits the spreadsheet.
*
* @param {Object} e The onEdit() event object.
*/
function onEdit(e) {
  if (!e) {
    throw new Error('Please do not run the script in the script editor window. It runs automatically when you manually edit the spreadsheet.');
  }
  hideRowsOnCheckboxClick_(e);
}


/**
* Runs when a checkbox is clicked in the range H1:K1.
* Hides all rows below frozen rows where the checkbox column is blank.
*
* @param {Object} e The onEdit() event object.
*/
function hideRowsOnCheckboxClick_(e) {
  // version 1.0, written by --Hyde, 19 September 2022
  //  - see https://stackoverflow.com/a/73774777/13045193
  if (e.value !== 'TRUE' || e.range.rowStart !== 1 || e.range.columnStart < 8 || e.range.columnStart > 11) {
    return;
  }
  const triggerValue = '';
  const sheet = e.range.getSheet();
  const lastRow = sheet.getLastRow();
  const rowStart = sheet.getFrozenRows() + 1;
  const numRows = lastRow - rowStart + 1;
  sheet.showRows(1, lastRow);
  const triggerColumn = sheet.getRange(rowStart, e.range.columnStart, numRows, 1);
  const rowsToHide = triggerColumn
    .getValues()
    .flat()
    .map((value, index) => value === triggerValue ? rowStart + index : 0)
    .filter(Number);
  countConsecutives_(rowsToHide)
    .forEach(group => sheet.hideRows(group[0], group[1]));
  e.range.setValue(false);
}


/**
* Counts consecutive numbers in an array and returns a 2D array that
* lists the first number of each run and the count of numbers in each run.
* Duplicate values in numbers will give duplicates in result.
*
* The numbers array [1, 2, 3, 5, 8, 9, 11, 12, 13, 5, 4] will get
* the result [[1, 3], [5, 1], [8, 2], [11, 3], [5, 1], [4, 1]].
*
* Typical usage:
* const runLengths = countConsecutives_(numbers.sort((a, b) => a - b));
*
* @param {Number[]} numbers The numbers to group into runs.
* @return {Number[][]} The numbers grouped into runs.
*/
function countConsecutives_(numbers) {
  return numbers.reduce(function (acc, value, index) {
    if (!index || value !== 1 + numbers[index - 1]) {
      acc.push([value]);
    }
    acc[acc.length - 1][1] = (acc[acc.length - 1][1] || 0) + 1;
    return acc;
  }, []);
}

I made an attempt at this, and when I read it I assumed multiple checkboxes should be able to be checked.

This is the code I came up with. Hopefully it's obvious what the three "let" variables are at the top and how to change them.

function onEdit(e){
  if (!e) {throw new Error('Please do not run the script in the script editor window. It runs automatically when you manually edit the spreadsheet.')}
  myFunction(e)
  }

function myFunction(e){
  let tabName          = 'Build Sample Here';
  let checkRangeString = 'H1:K1';
  let offsetToValues   = 2;

  var sheet = e.range.getSheet();
  if(sheet.getName()!= tabName){return}
  var checkRange = sheet.getRange(checkRangeString);
  if(e.range.rowStart != checkRange.getRow() || e.range.columnStart <checkRange.getColumn() || e.range.columnStart>checkRange.getLastColumn()){return}
  var checks = checkRange.getValues().flat();
  var lastRow = sheet.getLastRow();
  if(checks.reduce((a,b)=>!a && !b)){sheet.showRows(1,lastRow);return}
  
  var values = checkRange.offset(offsetToValues,0,sheet.getLastRow()-offsetToValues).getValues().map(e=>e.filter((f,i)=>checks[i]));
  if(!values.length){sheet.showRows(1,lastRow);return}
  values = values.map((e,i)=>[i,e.reduce((a,b)=>a+b)]).filter(e=>!e[1]).map(e=>e[0]+offsetToValues+1);

  var rowSets =[];
  for (let i=1,tempCount=1,startRow=offsetToValues+1;i<values.length;i++){
    if(values[i]==values[i-1]+1 && values[i]!=lastRow){tempCount ++;continue}
    if(values[i]==lastRow){tempCount++}
    rowSets.push([startRow,tempCount]);
    startRow = values[i];
    tempCount =1;
  }
  
  sheet.showRows(1,lastRow);
  rowSets.forEach(e=>sheet.hideRows(e[0],e[1]));
}
Related