查找Google表格中的所有复选框

问题描述 投票:0回答:2

自从2018年将复选框添加到本机Google表格UI以来,开发人员一直希望以编程方式阅读它们或以某些方式对待它们,例如将它们视为“单选按钮”,将它们重置为“未选中”,或将它们设置为“检查”。

我们如何才能最好地找到给定Google表格中的复选框,以便我们避免在操纵其状态时意外修改其他单元格?

一种方法是检查工作表上的值,并将任何true / false值视为复选框:

function getAllCheckboxes() {
  const wb = SpreadsheetApp.getActive();
  const checkboxes = [];

  wb.getSheets().forEach(function (sheet) {
    var rg = sheet.getDataRange();
    var values = rg.getValues();
    var sheetCheckBoxes = [];

    values.forEach(function (row, r) {
      row.forEach(function (val, c) {
        // Checkbox values are stored as `false` (unchecked) and `true` (checked)
        if (val === false || val === true) {
          sheetCheckBoxes.push({
            rowIndex: r,
            colIndex: c,
            value: val,
            r1c1: "R" + (r+1) + "C" + (c+1)
          });
        }
      });
    });
    if (sheetCheckBoxes.length) {
      checkboxes.push({
        name: sheet.getName(),
        sheetId: sheet.getSheetId(),
        boxes: sheetCheckBoxes
      });
    }
  });

  return checkboxes; // An array of objects describing a sheet and its checkboxes.
}

但是,这不适用于所有用例:单元格可能显示为文字TRUEFALSE,而不是复选框。上面的代码将它视为一个,因为它共享相同的值。

checkbox google-apps-script google-sheets google-sheets-api
2个回答
3
投票

复选框在Google表格应用程序中实现为数据验证的a specific type,并且可以具有“已检查”和“未选中”的用户指定值 - 而不仅仅是truefalse。因此,为了正确地找到仅作为复选框的单元格,我们必须使用应用于每个单元格的check the data validation type。这可以通过Google Apps脚本以两种方式完成:使用电子表格服务,或使用Google表格API(v4)。

Spreadsheet Service

电子表格服务方法不要求您启用任何其他符号标识符或启用Google Cloud Platform中的任何API。但是,在某些情况下,它可能不像Sheets API那么快。

该脚本与问题中的脚本非常相似,不同之处在于我们必须迭代2D数据验证规则数组,而不是值数组。 (如果我们不需要复选框的当前值,我们可以跳过获取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;
}

Sheets API

要使用Sheets API,必须首先在应用程序的Google Cloud Platform项目中启用它。对于Apps脚本项目,其中一个是自动创建的,可从Apps脚本编辑器的“资源”菜单中访问。如果您不确定如何激活the Advanced Services guide符号和Sheets REST API,请查看Sheets

spreadsheets.get部分响应掩码包含fields时,通过端点sheets/data/rowData/values/dataValidation检索数据验证。通常只是这个特定的字段没有用 - 知道关联的工作表的标题,ID以及复选框的值也很有用,所以更有用的fields规范是sheets(data(rowData(values(dataValidation,effectiveValue/boolValue))),properties(sheetId,title))。 (您可以在Google APIs Explorer中试验有效的字段掩码)

Sheets 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;
}

有效地使用复选框位置

一旦知道电子表格中的哪些单元格对应复选框 - 以及哪些值显示为“已检查”与“未选中”,则自然需要阅读或修改它们。盲目地将truefalse写入复选框单元格仅对默认有效( boolean)复选框。要处理所有可能的用户创建的复选框,必须编写适当的值,表示“已选中”或“未选中”。(上述脚本将这些值存储在choices属性中。)

使用RangeList类在Apps脚本中最容易重置值,尽管Sheets API端点spreadsheets.values.batchUpdate可以获得类似的结果(是的,对于Sheets API ValueRange规范,R1C1表示法是可接受的),尽管有一些构造请求的样板。 API方法能够发出单个请求,而电子表格服务只能实例化每张单个RangeList(并且您需要为每种类型的复选框创建1个RangeList,以避免写入不正确的值(例如,当“未选中”时false) “价值应该是"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);
  });
}

要从someCBs构建API请求,这样的东西就足够了:

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);
}

0
投票

这似乎有效:

function testForCheckBoxes() {
  var ss=SpreadsheetApp.getActive();
  var sh=ss.getActiveSheet();
  var rg=sh.getDataRange();
  var vA=rg.getDataValidations();
  var cbA=[];
  for(var i=0;i<vA.length;i++) {
    for(var j=0;j<vA[i].length;j++) {
      var rule=vA[i][j];
      if(rule!=null) {
        var criteria = rule.getCriteriaType();
        if(criteria == SpreadsheetApp.DataValidationCriteria.CHECKBOX) {
          cbA.push(Utilities.formatString('%s', sh.getRange(i+1,j+1).getA1Notation()));
        }
      }
    }
  }
  var ui=HtmlService.createHtmlOutput(cbA.join(', '));
  SpreadsheetApp.getUi().showModelessDialog(ui, 'Check Boxes in A1Notation')
}
© www.soinside.com 2019 - 2024. All rights reserved.