Флажки реализованы в приложении Google Sheets как определенный тип проверки данных, а может иметь указанные пользователем значения для "отмеченных" и "непроверенных" - не толькоtrue
и false
.Таким образом, чтобы правильно найти только ячеек, которые являются флажками, мы должны проверить тип проверки данных , который применяется к каждой ячейке.Это можно сделать в Google Apps Script двумя способами: с помощью службы электронных таблиц или с помощью Google Sheets API (v4).
служба электронных таблиц
Метод службы электронных таблиц не требует от васвключить любые дополнительные идентификаторы символов или включить любые API в Google Cloud Platform.Однако в некоторых случаях он может быть не таким быстрым, как API Sheets.
Сценарий очень похож на сценарий в вопросе, с той разницей, что мы должны повторять массив правил проверки двумерных данных, а немассив значений.(Если нам не нужно текущее значение флажка, мы можем пропустить получение массива values
.)
function getAllCheckboxesViaService() {
const wb = SpreadsheetApp.getActive();
const checkboxes = [];
// The specific type of Data Validation that demarcates a UI checkbox.
const CB = SpreadsheetApp.DataValidationCriteria.CHECKBOX;
wb.getSheets().forEach(function (sheet) {
var rg = sheet.getDataRange();
var values = rg.getValues();
var sheetCheckBoxes = [];
var dvRules = rg.getDataValidations();
dvRules.forEach(function (row, r) { // iterate data validations instead of values
row.forEach(function (rule, c) {
if (rule && rule.getCriteriaType() === CB) {
sheetCheckBoxes.push({
rowIndex: r,
colIndex: c,
r1c1: "R" + (r+1) + "C" + (c+1),
choices: (rule.getCriteriaValues().length ? rule.getCriteriaValues() : [true, false]),
value: values[r][c],
});
}
});
});
if (sheetCheckBoxes.length) {
checkboxes.push({
name: sheet.getName(),
sheetId: sheet.getSheetId(),
boxes: sheetCheckBoxes
});
}
});
return checkboxes;
}
API листов
Чтобы использовать API листов, он долженСначала включите его в проекте Google Cloud Platform приложения.Для проектов скриптов приложений один из них создается автоматически и доступен из меню «Ресурсы» в редакторе скриптов приложений.Просмотрите Руководство по расширенным услугам , если вы не знаете, как активировать символ Sheets
и API REST Sheets.
Проверка данных извлекается через конечную точку spreadsheets.get
, когда маска частичного ответа fields
включает sheets/data/rowData/values/dataValidation
.Обычно это конкретное поле бесполезно - также полезно знать заголовок, идентификатор и, возможно, значение флажка соответствующего листа, поэтому более полезной спецификацией fields
является sheets(data(rowData(values(dataValidation,effectiveValue/boolValue))),properties(sheetId,title))
.(Вы можете поэкспериментировать с действительными масками полей в Google API Explorer )
Соответствующий тип проверки данных в API листов - BOOLEAN
.Мы можем запросить нашу нужную электронную таблицу один раз через API, а затем локально проверить полученные данные ответа, чтобы определить, какие ячейки имеют флажки, а какие нет:
function getAllCheckboxesViaAPI() {
const wbId = SpreadsheetApp.getActive().getId();
const fields = "sheets(data/rowData/values("
+ "dataValidation(condition(type,values/userEnteredValue)),"
+ "effectiveValue(boolValue,numberValue,stringValue)),"
+ "properties(sheetId,title))";
const resp = Sheets.Spreadsheets.get(wbId, {fields: fields}); // Enable before use...
if (!resp.sheets || !resp.sheets.length)
return [];
const checkboxes = [];
resp.sheets.forEach(function (sheetObj) {
if (!sheetObj.data || !sheetObj.data.length)
return;
var sheetCheckBoxes = [];
sheetObj.data.forEach(function (gridRange) {
gridRange.rowData.forEach(function (row, r) {
row.values.forEach(function (cell, c) {
if (cell.dataValidation && cell.dataValidation.condition
// Require the cell to be displayed as a Checkbox.
&& cell.dataValidation.condition.type === "BOOLEAN")
{
sheetCheckBoxes.push({
rowIndex: r,
colIndex: c,
r1c1: "R" + (r+1) + "C" + (c+1),
choices: (cell.dataValidation.condition.values ?
cell.dataValidation.condition.values : [true, false]),
value: cell.effectiveValue // object, e.g. {booleanValue: false} or {stringValue: "Yes"}
});
}
});
});
});
checkboxes.push({
name: sheetObj.properties.title,
sheetId: sheetObj.properties.sheetId,
boxes: sheetCheckBoxes
});
});
return checkboxes;
}
Эффективное использование местоположений флажков
Как только кто-то знает, какие ячейки в электронной таблице соответствуют флажкам - и какие значения отображаются как «отмеченные» и «не отмечены», естественно захотеть прочитать или изменить их. Слепая запись true
или false
в ячейку флажка - толькодопустимо для стандартных (логических) флажков. Чтобы обработать все возможные пользовательские флажки, необходимо написать соответствующее значение, которое означает «проверено» или «не проверено». (Эти сценарии хранят эти значения в свойстве choices
.)
Сброс значений проще всего выполнить в скрипте Apps с помощью класса RangeList
, хотя конечная точка Sheets API spreadsheets.values.batchUpdate
может достичь аналогичных результатов (да, нотация R1C1приемлемо для спецификации API Sheets ValueRange
), хотя и с некоторыми образцами для построенияпросьбаПодход API может выдавать один запрос, в то время как служба электронных таблиц может создавать только один RangeList
на лист (и вам нужно будет создать 1 RangeList
для каждого типа флажка, чтобы избежать записи неправильных значений (например, false
когда значение "unchecked" должно быть "No"
)).
function getSpecificCBType(checkboxData, checkedVal, uncheckedVal) {
const desiredCBs = checkboxData.filter(function (sheetObj) {
return sheetObj.boxes.some(function (checkbox) {
return checkbox.choices[0] === checkedVal && checkbox.choices[1] === uncheckedVal;
});
}).reduce(function (acc, sheetObj) {
var desiredSheetCBs = sheetObj.boxes.filter(function (checkbox) {
return checkbox.choices[0] === checkedVal && checkbox.choices[1] === uncheckedVal;
});
if (desiredSheetCBs.length) {
acc.push({
name: sheetObj.name,
sheetId: sheetObj.sheetId,
boxes: desiredSheetCBs
});
}
return acc;
}, []);
return desiredCBs;
}
function resetSomeCBsViaService() {
const allCBs = /* method from above */;
const checkedValue = true;
const uncheckedValue = false;
const someCBs = getSpecificCBType(allCBs, checkedValue, uncheckedValue);
const wb = SpreadsheetApp.getActive();
// Set to checked, using a RangeList (could use Sheets API values#batchUpdate).
someCBs.forEach(function (sheetObj) {
wb.getSheetByName(sheetObj.name)
.getRangeList(sheetObj.boxes.map(function (checkbox) { return checkbox.r1c1; }))
.setValue(checkedValue);
});
}
Чтобы построить запрос API из someCBs
, достаточно примерно такого:
function resetSomeCBsViaAPI() {
const allCBs = /* method from above */;
const checkedValue = true;
const uncheckedValue = false;
const someCBs = getSpecificCBType(allCBs, checkedValue, uncheckedValue);
const wbId = SpreadsheetApp.getActive().getId();
const rq = someCBs.reduce(function (rqb, sheetObj) {
var valueRanges = sheetObj.boxes.map(function (checkbox) {
return {
range: "'" + sheetObj.name + "'!" + checkbox.r1c1,
values: [ [checkedValue] ]
};
});
Array.prototype.push.apply(rqb.data, valueRanges);
return rqb;
}, {valueInputOption: "USER_ENTERED", data: []});
Sheets.Spreadsheets.Values.batchUpdate(rq, wbId);
}