Недавно в комментариях «прилетел» следующий вопрос:
Здравствуйте!
А как настроить на флажки проверку данных ?
К примеру есть массив данных, скажем сверху я создаю два чекбокса «в работе» и «завершено» и при нажатии на любой мне соответственно отображаются только нужные значения (статус «в работе»).
Знаю как это реализовать через функцию FILTER , но для этого придется создавать вторую таблицу, что неудобно.
и хотя уточняющего ответа не было, задача показалась интересной и я решил попробовать ее реализовать.
Часть 1: Табличная
Тут все не сложно:
Создаю два чекбокса и подписываю, что они должны характеризовать по задаче:
Ниже делаю условную таблицу с задачами и их статусом:
Выпадающий список сделан на основе данных ячеек B1 и B2:
На этом собственно всё. Табличную часть можно считать законченной. Выглядит она следующим образом:
Часть 2: Скрипты
Перехожу в скрипты:
И первое, что делаю, обращаюсь к нужному листу книги и возвращаю массив со статусом задач:
const ss = SpreadsheetApp.getActiveSpreadsheet();
const wsStatus = ss.getSheetByName('Task');
function getAllStatus() {
const textToFind = "Статус"
const startRow = wsStatus.createTextFinder(textToFind).findNext().getRowIndex();
const endPosition = wsStatus.getLastRow();
let allStatus = [];
for (let i = startRow + 1; i <= endPosition; i++) {
allStatus.push([wsStatus.getRange('A' + i).getRowIndex(), wsStatus.getRange('A' + i).getValue()]);
}
return allStatus;
}
Выглядит вернувшийся массив так:
где первый элемент подмассива это номер строки, второй — статус.
Зачем нужно вот это:
const textToFind = "Статус"
const startRow = wsStatus.createTextFinder(textToFind).findNext().getRowIndex();
Скрипт находит текст «статус» и возвращает индекс его ряда: в данном примере это 4.
Я решил отказаться от фиксации первой строки, и того что будет забираться в массив по следующей причине: если добавить строки между чекбоксами и таблицей ниже, то будет ошибка.
for (let i = startRow + 1; i <= endPosition; i++) {
allStatus.push([wsStatus.getRange('A' + i).getRowIndex(), wsStatus.getRange('A' + i).getValue()]);
В итоге от строчки после шапки «Статус» идет сбор массива.
Следующий шаг это раскрыть весь список, независимо от того, что могло быть ранее скрыто:
function unhideAll() {
for (let elem of getAllStatus()) {
wsStatus.unhideRow(wsStatus.getRange(`A${elem[0]}`))
}
}
то есть каждая строка (а именно с 5 по 13 включительно) указанная в getAllStatus()
будет раскрыта.
Следующая функция получает состояние нажатых чекбоксов:
function checkBoxResults() {
if (wsStatus.getRange('A1').getValue() && wsStatus.getRange('A2').getValue()) {
return 2;
} else if (wsStatus.getRange('A1').getValue()) {
return 1;
} else if (wsStatus.getRange('A2').getValue()) {
return 3;
} else {
return 0;
}
}
wsStatus.getRange('A1').getValue() && wsStatus.getRange('A2').getValue()
— если нажаты оба, вернуть цифру 2
wsStatus.getRange('A1').getValue()
— если только первый, возвращается 1
wsStatus.getRange('A2').getValue()
— если только второй, возвращается 3
Во всех остальных случаях возвращается 0.
Ну и последняя функция — для отображения нужных строк:
function filterStatus() {
const allStatusRow = getAllStatus()
const checkBoxSum = checkBoxResults()
let filteredArr = []
switch (checkBoxSum) {
case 1:
filteredArr = allStatusRow.filter(row => row[1] !== wsStatus.getRange('B1').getValue())
unhideAll();
for (let elem of filteredArr) {
wsStatus.hideRow(wsStatus.getRange(`A${elem[0]}`))
}
break;
case 2:
filteredArr = allStatusRow.filter(row => (row[1] !== wsStatus.getRange('B1').getValue() && row[1] !== wsStatus.getRange('B2').getValue()))
unhideAll();
for (let elem of filteredArr) {
wsStatus.hideRow(wsStatus.getRange(`A${elem[0]}`))
}
break;
case 3:
filteredArr = allStatusRow.filter(row => row[1] !== wsStatus.getRange('B2').getValue())
unhideAll();
for (let elem of filteredArr) {
wsStatus.hideRow(wsStatus.getRange(`A${elem[0]}`))
}
break;
default:
unhideAll();
break;
}
}
const allStatusRow = getAllStatus()
— получаю весь массив
const checkBoxSum = checkBoxResults()
— получаю значения 0-1-2-3 по нажатым чекбоксам
Далее через switch (case)
фильтрую массив на основе выбранных чекбоксов и прячу необходимые строки, например по case 1:
case 1:
filteredArr = allStatusRow.filter(row => row[1] !== wsStatus.getRange('B1').getValue())
unhideAll();
for (let elem of filteredArr) {
wsStatus.hideRow(wsStatus.getRange(`A${elem[0]}`))
}
break;
filteredArr = allStatusRow.filter(row => row[1] !== wsStatus.getRange('B1').getValue())
— массив где указаны строки НЕ равные смыслу нажатого чекбокса.
unhideAll();
— принудительно сначала все раскрываю.
wsStatus.hideRow(wsStatus.getRange(`A${elem[0]}`))
— скрываю строку которая НЕ равна смыслу нажатого чекбокса.
Далее необходимо функцию filterStatus()
повесить в onEdit()
:
function onEdit(){
filterStatus()
}
Потом сохраниться и обновить таблицу.
Теперь при нажатии на чекбоксы ненужные статусы будут прятаться: