用于工作表的谷歌应用脚​​本 - 选择多个列表值并记录在同一个单元格中

Posted

技术标签:

【中文标题】用于工作表的谷歌应用脚​​本 - 选择多个列表值并记录在同一个单元格中【英文标题】:google app script for sheets - select multiple list values and record in same cell 【发布时间】:2017-02-16 11:02:48 【问题描述】:

我正在尝试在 Google 表格中复制我能够在 Excel 中执行的操作:选择多个列表值并在同一个单元格中记录。

我用过这个视频:

https://www.youtube.com/watch?v=8x6YUsl7Ld4&feature=youtu.be

还有这段代码:

Private Sub Worksheet_Change(ByVal Target As Range)
'Code by Sumit Bansal from www.trumpexcel.com
' To Select Multiple Items from a Drop Down List in Excel
Dim Oldvalue As String
Dim Newvalue As String
On Error GoTo Exitsub
    If Target.SpecialCells(xlCellTypeAllValidation) Is Nothing Then
    GoTo Exitsub
    Else: If Target.Value = "" Then GoTo Exitsub Else
        Application.EnableEvents = False
        Newvalue = Target.Value
        Application.Undo
        Oldvalue = Target.Value
        If Oldvalue = "" Then
            Target.Value = Newvalue
        Else
            Target.Value = Oldvalue & ", " & Newvalue
        End If
    End If
Application.EnableEvents = True
Exitsub:
Application.EnableEvents = True
End Sub

并设法让它在 Excel 中工作,却发现该功能会在 Google 表格中丢失。

请告诉我 Google Apps 脚本中的等效代码以及放置位置?

【问题讨论】:

【参考方案1】:

这是通过 google-apps-script 执行相同操作的脚本。不过需要注意的是 1.数据验证应启用Show warning而不是Reject Input,如下所示 2.选择多个项目后,考虑中的单元格会显示警告。(我不知道如何轻松关闭它)。减少单元格上烦人警告的一种方法是为单元格添加帮助上下文“忽略任何警告”,方法是选中上图中的框 Show validation help text:。 3. 该行为适用于有数据验证的ALL范围,因此请注意将ONLY应用于您关心的范围。

function onEdit(e)
  var editedRange=e.range;
  var rule = editedRange.getDataValidation();
  if(rule!=null) //Act only if the cell has a data validation
    if (!(e.value.equals("") || e.oldValue == null)) //No need to do anything funky if user clears everything or if previous contents were empty
      if(e.oldValue.indexOf(e.value) !=-1) //Check if new selected value has already been chosen before 
        editedRange.setValue(e.oldValue) //If already chosen then don't select again.
      else
        editedRange.setValue(e.oldValue+","+e.value) // Show old+new selection.

onEdit 是一个简单的触发函数,每次对电子表格进行编辑时都会调用它(任何个人 Sheets )。eEvent Object,其中包含有关编辑的信息发生了。 您可以找到更多关于同一 here 的文档。 如果您想以编程方式设置数据验证,this 也可能会有所帮助。

【讨论】:

¿我怎样才能仅将其应用于一列? @xav56883728 确保在上图中显示的是Sheet1!A:A【参考方案2】:

您可以创建一个对话框,将每个可用选项显示为复选框,并根据用户选择设置单元格数据。

以下是一些示例数据:

以及此类对话框的行为方式:

为此,您必须首先创建一个包含四个函数的脚本文件。一个向对话框公开菜单,另一个显示对话框,第三个处理选项并将选项传递给对话框,最后一个设置从对话框发送的单元格中的数据。见下面代码:

function onOpen() 
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const multiselectMenu = name: 'Select multiple', functionName: 'showSelectDialog'
  ss.addMenu("My Scripts", [multiselectMenu]);


function showSelectDialog()
  const template = htmlService.createTemplateFromFile('dialog');
  template.optionsData = getOptionsFromCurrentCell();
  const html = template.evaluate();
  SpreadsheetApp.getUi().showModalDialog(html, 'Select multiple');


function getOptionsFromCurrentCell()
  const validOptions = SpreadsheetApp
    .getActiveRange() // everything that is selected
    .getDataValidation() // all validation rules for that
    .getCriteriaValues()[0] // the first criteria
    .getValues() // the value for this criteria
    .map(value => value[0]); // flatten in an one dimension array

  const selectedOptions = SpreadsheetApp
    .getActiveRange()
    .getCell(1, 1) // first selected cell in the range
    .getValue()
    .split(',') // convert the cell string into an array
    .map(str => str.trim()); // remove unwanted whitespace

  const optionsData = validOptions.map(option => 
    return 
      value: option,
      isSelected: selectedOptions.includes(option)
    
  )

  return optionsData;


function setOptionsForCurrentCell(selectedOptions)
  const hasOptions = Array.isArray(selectedOptions) 
    && selectedOptions.length > 0
  const cellData = hasOptions
    ? selectedOptions.join(',') // creates a comma separated string
    : '';
  const cell = SpreadsheetApp.getActiveRange().getCell(1, 1);
  cell.setValue(cellData);  

然后您在脚本编辑器中创建一个 Html 文件以呈现对话框并将选定的选项传回电子表格。见:

<!DOCTYPE html>
<html>
  <body>
    <? for (const option of optionsData)  ?>
      <input 
        type="checkbox" 
        class="option" 
        value="<?= option.value ?>" 
        <?= option.isSelected && "checked" ?>
      >
      <label><?= option.value ?></label><br>
    <?  ?>
    <div style="margin-top:10px;">
      <input 
        type="button" 
        value="all" 
        onclick="setAll('check')"
      />
      <input 
        type="button" 
        value="clear" 
        onclick="setAll('clear')" 
      />
      <input 
        type="button"
        value="cancel"
        onclick="google.script.host.close()"
      />
      <input 
        type="button"
        value="apply"
        onclick="apply()"
      />
    </div>
    <script>      
      function setAll(value) 
        const optionsEl = document
          .querySelectorAll(".option");
        for (const checkbox of optionsEl) 
          checkbox.checked = value === 'check';
        
      

      function apply()
        const checkedEls = document
          .querySelectorAll(".option:checked");
        const selectedValues = [];
        for (const checkbox of checkedEls) 
          if (checkbox.checked) 
             selectedValues.push(checkbox.value);
          
        
        google.script.run
          .setOptionsForCurrentCell(selectedValues);
        google.script.host.close();
      
    </script>
  </body>
</html>

应该可以。如果您需要此解决方案的分步指南,请查看此post。

【讨论】:

以上是关于用于工作表的谷歌应用脚​​本 - 选择多个列表值并记录在同一个单元格中的主要内容,如果未能解决你的问题,请参考以下文章

如何使用谷歌应用脚​​本找到最后一列?

使用谷歌应用脚​​本更新数据验证规则时如何保留原始范围

谷歌应用脚​​本从 gmail 中删除特定附件

如何在谷歌应用脚​​本中将段落 html 字符串转换为没有 html 标签的纯文本?

谷歌应用脚​​本没有循环

用于设置自定义变量的谷歌分析新版本