【问题标题】:Selectable optgroup using select2使用 select2 的可选 optgroup
【发布时间】:2015-01-13 21:44:04
【问题描述】:

我已经使用 select2 从下拉列表中选择多个选项,但是 select2 是否可以选择完整的 optgroup?我想要的是当用户选择选项组时,应该选择所有子选项。我想使用 jQuery Select2 来做到这一点。我怎么能这样做?

【问题讨论】:

标签: jquery html jquery-select2


【解决方案1】:

如果您使用隐藏的输入元素而不是选择元素来支持 Select2,这是可能的。

要使组选项可选择,您必须给它一个“id”,但它似乎可以是一个空字符串。然后,您可以使用“select2-selecting”事件来阻止选择组选项,而是选择其子选项。

此外,可以提供一个query 函数来防止一个组选项在其所有子选项都被选中后出现在列表中。

如果您有这样定义的选项:

var FRUIT_GROUPS = [
    {
        id: '',
        text: 'Citrus',
        children: [
            { id: 'c1', text: 'Grapefruit' },
            { id: 'c2', text: 'Orange' },
            { id: 'c3', text: 'Lemon' },
            { id: 'c4', text: 'Lime' }
        ]
    },
    {
        id: '',
        text: 'Other',
        children: [
            { id: 'o1', text: 'Apple' },
            { id: 'o2', text: 'Mango' },
            { id: 'o3', text: 'Banana' }
        ]
    }
];

您可以像这样检测您的 Select2:

$('#fruitSelect').select2({
    multiple: true,
    placeholder: "Select fruits...",
    data: FRUIT_GROUPS,
    query: function(options) {
        var selectedIds = options.element.select2('val');
        var selectableGroups = $.map(this.data, function(group) {
            var areChildrenAllSelected = true;
            $.each(group.children, function(i, child) {
                if (selectedIds.indexOf(child.id) < 0) {
                    areChildrenAllSelected = false;
                    return false; // Short-circuit $.each()
                }
            });
            return !areChildrenAllSelected ? group : null;
        });
        options.callback({ results: selectableGroups });
    }
}).on('select2-selecting', function(e) {
    var $select = $(this);
    if (e.val == '') { // Assume only groups have an empty id
        e.preventDefault();
        $select.select2('data', $select.select2('data').concat(e.choice.children));
        $select.select2('close');
    }
});

jsfiddle

这是一个没有query 函数的jsfiddle,当所有子选项都被选中时,组选项仍然出现。

【讨论】:

  • 嗨,谢谢你的回答,但这条线有什么作用? $select.select2('val', $select.select2('val').concat(childIds));我拥有的是一个带有 optgroups 的 html 选项列表,我希望它与我的结合,但无法获得这一行
  • 是否可以在选择组名称下选择所有选项时显示“所有选项已选择”???
  • @user1269524 - $select.select2('val', $select.select2('val').concat(childIds)); 行设置选定的选项。它将所选父选项的所有子选项添加到所有先前选择的选项中,然后将该列表提供给 Select2 控件。
  • @user1269524 - 我无法让它与&lt;select 元素一起使用,因为我看不到使&lt;optgroup&gt; 元素可选的方法。您必须切换到使用隐藏的输入元素和我展示的数据。
  • @user1269524 - 我更新了我的答案。我包含了一个新的jsfiddle,如果它的所有子项都被选中,它会隐藏一个组选项。如果你愿意,你可以让它改变文本。
【解决方案2】:

我找到了一个用于 Select2 v4 的插件,它增加了单击 optgroup 以选择/取消选择所有子选项的功能。它对我来说非常有效。 bnjmnhndrsn/select2-optgroup-select

感谢本·亨德森!

【讨论】:

    【解决方案3】:

    我使用了 John 的代码,但我的问题是我需要过滤功能,所以我添加了它。您可以看到代码在 jsfiddle 上运行。

    这是查询代码:

             query: function (options) {
                var selectedIds = options.element.select2('val');
                var data = jQuery.extend(true, {}, FRUIT_GROUPS);
                var selectableGroups = $.map(data, function (group) {
                    var areAllChildrenSelected = true,
                        parentMatchTerm = false,
                        anyChildMatchTerm = false;
                    if (group.text.toLowerCase().indexOf(options.term.toLowerCase()) >= 0) {
                        parentMatchTerm = true;
                    }
                    var i = group.children.length
                    while (i--) {
                        var child = group.children[i];
    
                        if (selectedIds.indexOf(child.id) < 0) {
                            areAllChildrenSelected = false;
                        };
    
                        if (options.term == '' || (child.text.toLowerCase().indexOf(options.term.toLowerCase()) >= 0)) {
                            anyChildMatchTerm = true;
                        }
                        else if (!parentMatchTerm) {
                            var index = group.children.indexOf(child);
                            if (index > -1) {
                                group.children.splice(index, 1);
                            };
                        };
                    };
    
                    return (!areAllChildrenSelected && (parentMatchTerm || anyChildMatchTerm)) ? group : null;
                });
    
                options.callback({ results: selectableGroups });
            }
    

    【讨论】:

    【解决方案4】:

    首先为您的选择提供 id 例如

    &lt;select style="width: 95%" id="selectgroup"&gt;

    然后将类添加到您的 optgroup 中,例如

     <optgroup value="ATZ" label="Alaskan/Hawaiian Time Zone" class="select2-result-selectable">
    

    然后添加这个

    $('#selectgroup').select2({
    
        }).on('select2-selecting', function (e) {
            debugger;
            var $select = $(this);
            if (e.val == undefined) {
                e.preventDefault();
                var childIds = $.map(e.choice.children, function (child) {
                    return child.id;
                });
                $select.select2('val', $select.select2('val').concat(childIds));
                $select.select2('close');
           }
        });
    

    如果你点击 optgroup 那么它将选择 optgroup 下的所有选项。

    【讨论】:

      【解决方案5】:

      在 Select2 v4 中,我发现 John S 的答案不起作用 (see here)。我正在使用 AJAX 将数据加载为数组并创建了一个解决方法:

      $(document).on("click", ".select2-results__group", function(){
          var input = $(this);
          var location = input.html();
          // Find the items with this location
          var options = $('#select2 option');
          $.each(options, function(key, value){
              var name = $(value).html();
              // The option contains the location, so mark it as selected
              if(name.indexOf(location) >= 0){
                  $(value).prop("selected","selected");
              }
          });
          $("#select2").trigger("change");
      });
      

      我按位置对我的项目进行分组,每个选项都在其 html 中的某处包含位置名称。每次单击 optgroup 标题时,我都会得到它的位置(下拉菜单中显示的名称)。然后我查看#select2 表中的所有选项,并在其 html 中找到包含该位置的选项。

      我知道这是一个 hacky 解决方法,但希望它有助于/指向正确的方向。

      【讨论】:

        【解决方案6】:

        好吧,我遇到了这个问题,我发现每次打开 select2 (Select2 4.0.5) 时,它都会在关闭 body 元素之前添加一个 span 元素。此外,在 span 元素内部添加了一个 ul,其 id 为:select2-X-results,其中 X 是 select2 id。 所以我找到了以下解决方法(jsfiddle):

        var countries = [{
          "id": 1,
          "text": "Greece",
          "children": [{
            "id": "Athens",
            "text": "Athens"
          }, {
            "id": "Thessalonica",
            "text": "Thessalonica"
          }]
        }, {
          "id": 2,
          "text": "Italy",
          "children": [{
            "id": "Milan",
            "text": "Milan"
          }, {
            "id": "Rome",
            "text": "Rome"
          }]
        }];
        
        $('#selectcountry').select2({
          placeholder: "Please select cities",
          allowClear: true,
          width: '100%',
          data: countries
        });
        
        $('#selectcountry').on('select2:open', function(e) {
        
          $('#select2-selectcountry-results').on('click', function(event) {
        
            event.stopPropagation();
            var data = $(event.target).html();
            var selectedOptionGroup = data.toString().trim();
        
            var groupchildren = [];
        
            for (var i = 0; i < countries.length; i++) {
        
        
              if (selectedOptionGroup.toString() === countries[i].text.toString()) {
        
                for (var j = 0; j < countries[i].children.length; j++) {
        
                  groupchildren.push(countries[i].children[j].id);
        
                }
        
              }
        
        
            }
        
        
            var options = [];
        
            options = $('#selectcountry').val();
        
            if (options === null || options === '') {
        
              options = [];
        
            }
        
            for (var i = 0; i < groupchildren.length; i++) {
        
              var count = 0;
        
              for (var j = 0; j < options.length; j++) {
        
                if (options[j].toString() === groupchildren[i].toString()) {
        
                  count++;
                  break;
        
                }
        
              }
        
              if (count === 0) {
                options.push(groupchildren[i].toString());
              }
            }
        
            $('#selectcountry').val(options);
            $('#selectcountry').trigger('change'); // Notify any JS components that the value changed
            $('#selectcountry').select2('close');    
        
          });
        });
        li.select2-results__option strong.select2-results__group:hover {
          background-color: #ddd;
          cursor: pointer;
        }
        <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
        <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/css/select2.min.css" rel="stylesheet"/>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/js/select2.full.min.js"></script>
        
        
        <h1>Selectable optgroup using select2</h1>
        <select id="selectcountry" name="country[]" class="form-control" multiple style="width: 100%"></select>

        【讨论】:

          【解决方案7】:

          使用选择元素的 V 4.0.2 的一个选项:

          <select style="width:100%;" id="source" multiple="" tabindex="-1" aria-hidden="true">                 
             <optgroup class="select2-result-selectable" label="Statuses"   >        
                <option value="1">Received</option>                          
                <option value="2">Pending Acceptance</option>                             
             </optgroup>                                 
             <optgroup class="select2-result-selectable" label="Progress" >                
                <option value="6">In Progress</option>
                <option value="7">Follow Up</option>                         
            </optgroup>                                                    
          </select>
          

          JS + JQuery:

          $(document).ready(function() {
          
             $('#source').select2();
          
          $(document).on("click", ".select2-results__group", function(){
          
              var groupName = $(this).html()
              var options = $('#source option');
          
              $.each(options, function(key, value){
          
                  if($(value)[0].parentElement.label.indexOf(groupName) >= 0){
                      $(value).prop("selected","selected");
                  }
          
              });
          
              $("#source").trigger("change");
              $("#source").select2('close'); 
          
            });
          });
          

          小提琴:https://jsfiddle.net/un1oL8w0/4/

          【讨论】:

            【解决方案8】:

            John S,提供的示例在大多数情况下都非常有效(对于 V3)。但是它有一个错误:

            假设选择列表足够长,可以滚动。当您选择仅在向下滚动后才可用的任何组中的任何项目时 - 您无法再选择您从该组中选择的项目之后的下一个项目。这是因为 select2 的 ensureHighlightVisible 方法开始出现异常,因为它使用的选择器使用 group 始终“不可选择”的假设。因此,每次您尝试选择项目时,滚动都会跳转。

            不幸的是,虽然这个解决方案看起来非常好 - 我放弃了它并在不使用组 ID 的情况下重新实现了它:

            $selectEl..on("select2-open", function(event) {
                      $(event.target).data("select2").dropdown.on("click", "li.select2-result-unselectable", selectGroup);
                      $(event.target).data("select2").dropdown.on("mousemove-filtered", "li.select2-result-unselectable", highlight);
                    }).on("select2-close", function(event) {
                      $(event.target).data("select2").dropdown.off("click", "li.select2-result-unselectable", selectGroup);
                      $(event.target).data("select2").dropdown.off("mousemove-filtered", "li.select2-result-unselectable", highlight);
                    });
            

              // selection of the group.
              function selectGroup(e) {
                var $li = $(this);
                e.preventDefault();
                $select.select2('data', $select.select2('data').concat($li.data("select2Data").children));
                $select.select2('close');
                _this.$field.trigger('change');
              }
            
              // highlight of the group.
              function highlight(e) {
                if ($(e.target).hasClass("select2-result-unselectable") || $(e.target.parentNode).hasClass('select2-result-unselectable')) {
                  e.preventDefault();
                  e.stopPropagation();
                  $select.data("select2").dropdown.find(".select2-highlighted").removeClass("select2-highlighted");
                  $(this).addClass("select2-highlighted");
                }
              }
            

            【讨论】:

              猜你喜欢
              • 2015-08-29
              • 1970-01-01
              • 1970-01-01
              • 2019-02-08
              • 1970-01-01
              • 2016-03-30
              • 2019-12-18
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多