Validation 如何在谷歌表单中实现动态/相关下拉列表?

Validation 如何在谷歌表单中实现动态/相关下拉列表?,validation,google-apps-script,google-sheets,Validation,Google Apps Script,Google Sheets,如何让子类别列根据在google sheets的主类别下拉列表中选择的值填充下拉列表 我在谷歌上到处搜索,找不到任何好的解决方案,所以我想分享我自己的。请看下面我的答案。您可以从设置了主页的google工作表开始,然后下拉源页面,如下所示 您可以通过普通数据>验证菜单提示设置第一列下拉列表 主页 下拉源页面 之后,您需要设置一个名为onEdit的脚本。(如果不使用该名称,getActiveRange()将只返回单元格A1) 并使用此处提供的代码: function onEdit() {

如何让子类别列根据在google sheets的主类别下拉列表中选择的值填充下拉列表


我在谷歌上到处搜索,找不到任何好的解决方案,所以我想分享我自己的。请看下面我的答案。

您可以从设置了主页的google工作表开始,然后下拉源页面,如下所示

您可以通过普通数据>验证菜单提示设置第一列下拉列表

主页

下拉源页面

之后,您需要设置一个名为
onEdit
的脚本。(如果不使用该名称,getActiveRange()将只返回单元格A1)

并使用此处提供的代码:

function onEdit() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = SpreadsheetApp.getActiveSheet();
  var myRange = SpreadsheetApp.getActiveRange();
  var dvSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Categories");
  var option = new Array();
  var startCol = 0;

  if(sheet.getName() == "Front Page" && myRange.getColumn() == 1 && myRange.getRow() > 1){
    if(myRange.getValue() == "Category 1"){
      startCol = 1;
    } else if(myRange.getValue() == "Category 2"){
      startCol = 2;
    } else if(myRange.getValue() == "Category 3"){
      startCol = 3;
    } else if(myRange.getValue() == "Category 4"){
      startCol = 4;
    } else {
      startCol = 10
    }

  if(startCol > 0 && startCol < 10){
    option = dvSheet.getSheetValues(3,startCol,10,1);
    var dv = SpreadsheetApp.newDataValidation();
    dv.setAllowInvalid(false);  
    //dv.setHelpText("Some help text here");
    dv.requireValueInList(option, true);
    sheet.getRange(myRange.getRow(),myRange.getColumn() + 1).setDataValidation(dv.build());
   }

  if(startCol == 10){
    sheet.getRange(myRange.getRow(),myRange.getColumn() + 1).clearDataValidations();
  } 
  }
}
函数onEdit(){
var ss=SpreadsheetApp.getActiveSpreadsheet();
var sheet=SpreadsheetApp.getActiveSheet();
var myRange=SpreadsheetApp.getActiveRange();
var dvSheet=SpreadsheetApp.getActiveSpreadsheet().getSheetByName(“类别”);
var option=newarray();
var-startCol=0;
如果(sheet.getName()==“首页”&&myRange.getColumn()==1&&myRange.getRow()>1){
如果(myRange.getValue()=“类别1”){
startCol=1;
}else if(myRange.getValue()=“类别2”){
startCol=2;
}else if(myRange.getValue()=“类别3”){
startCol=3;
}else if(myRange.getValue()=“类别4”){
startCol=4;
}否则{
startCol=10
}
如果(startCol>0&&startCol<10){
option=dvSheet.getSheetValues(3,startCol,10,1);
var dv=SpreadsheetApp.newDataValidation();
dv.setAllowInvalid(false);
//dv.setHelpText(“此处的一些帮助文本”);
dv.RequiremeEinList(选项,true);
sheet.getRange(myRange.getRow(),myRange.getColumn()+1).setDataValidation(dv.build());
}
如果(startCol==10){
sheet.getRange(myRange.getRow(),myRange.getColumn()+1).clearDataValidations();
} 
}
}
之后,在脚本编辑器屏幕中转到Edit>CurrentProject Triggers设置触发器。这将打开一个窗口,让您选择各种下拉列表,最终以以下方式结束:


你应该很乐意去做那件事

编辑:下面的答案可能令人满意,但也有一些缺点:

  • 脚本的运行有明显的停顿。我有160毫秒的延迟,这足以让人恼火

  • 它的工作原理是每次编辑给定行时构建一个新范围。这会在某些时候为以前的条目提供“无效内容”

  • 我希望其他人能清理一下

    下面是另一种方法,它可以为您节省大量的范围命名:

    工作表中的三张工作表:分别称为“主工作表”、“列表工作表”和“绘图工作表”(用于动态范围) 在主工作表上,第1列包含时间戳。此时间戳已修改为OneEdit

    在列表中,您的类别和子类别被安排为一个简单的列表。我在我的林场里用这个作为植物目录,所以我的列表如下所示:

    Group   | Genus | Bot_Name
    Conifer | Abies | Abies balsamea
    Conifer | Abies | Abies concolor
    Conifer | Abies | Abies lasiocarpa var bifolia
    Conifer | Pinus | Pinus ponderosa
    Conifer | Pinus | Pinus sylvestris
    Conifer | Pinus | Pinus banksiana
    Conifer | Pinus | Pinus cembra
    Conifer | Picea | Picea pungens
    Conifer | Picea | Picea glauca
    Deciduous | Acer | Acer ginnala
    Deciduous | Acer | Acer negundo
    Deciduous | Salix | Salix discolor
    Deciduous | Salix | Salix fragilis
    ...
    
    其中|表示分栏。
    为了方便起见,我还将标题用作命名范围的名称

    DRrange A1具有以下公式:

    =Max(Main!A2:A1000)
    
    这将返回最近的时间戳

    A2至A4在以下方面有变化:

    =vlookup($A$1,Inventory!$A$1:$E$1000,2,False) 
    
    对于右侧的每个单元格,2递增

    运行A2至A4时,将具有当前选定的组、属和种

    在每一个命令下面都有一个类似以下内容的筛选器命令:

    Group   | Genus | Bot_Name
    Conifer | Abies | Abies balsamea
    Conifer | Abies | Abies concolor
    Conifer | Abies | Abies lasiocarpa var bifolia
    Conifer | Pinus | Pinus ponderosa
    Conifer | Pinus | Pinus sylvestris
    Conifer | Pinus | Pinus banksiana
    Conifer | Pinus | Pinus cembra
    Conifer | Picea | Picea pungens
    Conifer | Picea | Picea glauca
    Deciduous | Acer | Acer ginnala
    Deciduous | Acer | Acer negundo
    Deciduous | Salix | Salix discolor
    Deciduous | Salix | Salix fragilis
    ...
    
    =唯一(筛选器(Bot\u名称,REGEXMATCH(Bot\u名称,C1)))

    这些过滤器将使用与顶部单元格内容匹配的条目填充下面的块

    过滤器可以根据您的需要和列表的格式进行修改

    返回Main:Main中的数据验证是使用DRange中的范围来完成的

    我使用的脚本:

    function onEdit(event) {
    
      //SETTINGS
      var dynamicSheet='DRange'; //sheet where the dynamic range lives
      var tsheet = 'Main'; //the sheet you are monitoring for edits
      var lcol = 2; //left-most column number you are monitoring; A=1, B=2 etc
      var rcol = 5; //right-most column number you are monitoring
      var tcol = 1; //column number in which you wish to populate the timestamp
      //
    
      var s = event.source.getActiveSheet();
      var sname = s.getName();
      if (sname == tsheet) {
        var r = event.source.getActiveRange();
        var scol = r.getColumn();  //scol is the column number of the edited cell
        if (scol >= lcol && scol <= rcol) {
          s.getRange(r.getRow(), tcol).setValue(new Date());
          for(var looper=scol+1; looper<=rcol; looper++) {
             s.getRange(r.getRow(),looper).setValue(""); //After edit clear the entries to the right
          }
        }
      }
    }
    
    函数onEdit(事件){
    //背景
    var dynamicSheet='DRange';//动态范围所在的工作表
    var tsheet='Main';//正在监视编辑的工作表
    var lcol=2;//您正在监视的最左边的列号;A=1,B=2等
    var rcol=5;//您正在监视的最右边的列号
    var tcol=1;//要填充时间戳的列号
    //
    var s=event.source.getActiveSheet();
    var sname=s.getName();
    如果(sname==T表){
    var r=event.source.getActiveRange();
    var scol=r.getColumn();//scol是已编辑单元格的列号
    
    如果(scol>=lcol&&scol这里您有另一个基于@tarheel提供的解决方案

    function onEdit() {
        var sheetWithNestedSelectsName = "Sitemap";
        var columnWithNestedSelectsRoot = 1;
        var sheetWithOptionPossibleValuesSuffix = "TabSections";
    
        var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
        var activeSheet = SpreadsheetApp.getActiveSheet();
    
        // If we're not in the sheet with nested selects, exit!
        if ( activeSheet.getName() != sheetWithNestedSelectsName ) {
            return;
        }
    
        var activeCell = SpreadsheetApp.getActiveRange();
    
        // If we're not in the root column or a content row, exit!
        if ( activeCell.getColumn() != columnWithNestedSelectsRoot || activeCell.getRow() < 2 ) {
            return;
        }
    
        var sheetWithActiveOptionPossibleValues = activeSpreadsheet.getSheetByName( activeCell.getValue() + sheetWithOptionPossibleValuesSuffix );
    
        // Get all possible values
        var activeOptionPossibleValues = sheetWithActiveOptionPossibleValues.getSheetValues( 1, 1, -1, 1 );
    
        var possibleValuesValidation = SpreadsheetApp.newDataValidation();
        possibleValuesValidation.setAllowInvalid( false );
        possibleValuesValidation.requireValueInList( activeOptionPossibleValues, true );
    
        activeSheet.getRange( activeCell.getRow(), activeCell.getColumn() + 1 ).setDataValidation( possibleValuesValidation.build() );
    }
    
    函数onEdit(){
    var sheetWithNestedSelectsName=“站点地图”;
    var columnWithNestedSelectsRoot=1;
    var表,带有选项PossibleValuesOffix=“TabSections”;
    var activeSpreadsheet=SpreadsheetApp.getActiveSpreadsheet();
    var activeSheet=SpreadsheetApp.getActiveSheet();
    //如果我们不在嵌套选择的工作表中,请退出!
    如果(activeSheet.getName()!=sheetWithNestedSelectsName){
    返回;
    }
    var activeCell=SpreadsheetApp.getActiveRange();
    //如果我们不在根列或内容行中,请退出!
    if(activeCell.getColumn()!=columnWithNestedSelectsRoot | | activeCell.getRow()<2){
    返回;
    }
    var sheetWithActiveOptionPossibleValues=activeSpreadsheet.getSheetByName(activeCell.getValue()+SheetWithOptionPossibleValuesOffix);
    //获取所有可能的值
    var activeOptionPossibleValues=sheetWithActiveOptionPossibleValues.getSheetValues(1,1,-1,1);
    var possibleValuesValidation=SpreadsheetApp.newDataValidation();
    possibleValuesValidation.setAllowInvalid(false);
    possibleValuesValidation.RequiremeWainList(activeOptionPossibleValues,true);
    activeSheet.getRange(activeCell.getRow(),activeCell.getColumn()+1).setDataValidation(possibleValuesValidation.build());
    }
    
    它有