Selectable optgroup with select2

I used select2 to select multiple options from the drop-down list, but is it possible to select select2 for the full opt group? What I want is when the user selects a group of parameters, all child parameters should be selected. And I want to do this with jQuery Select2 . How can i do this?

+9
jquery html jquery-select2
source share
7 answers

This is possible if you return Select2 with a hidden input element - instead of the select element.

To make a group selection, you must specify "id", but it seems to be an empty string. Then you can use the "select2-selection" event to prevent the group from being selected, and instead select its child parameters.

In addition, a query function can be provided to prevent a group parameter from appearing in the list after all its child parameters have been selected.

If you have parameters defined as follows:

 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' } ] } ]; 

You can customize your Select2 as follows:

 $('#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

Here is jsfiddle without the query function, where group parameters still appear when all their child parameters are selected.

+19
source share

I used John's code, but my problem was that I needed the ability to filter, so I added it. You can see the code working on jsfiddle .

This is the request code:

  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 }); } 
+2
source share

First specify the id for the selected example

<select style="width: 95%" id="selectgroup">

and then add the class to your opt group, for example

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

and then add this

 $('#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'); } }); 

If you click on optgroup, then it will select all the options under optgroup.

+2
source share

In Select2 v4, I found that John C.'s answer would not work ( see here ). I load my data as an array using AJAX and create a workaround:

 $(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"); }); 

I am grouping my items by location, and each parameter contains a location name somewhere in it html. Each time I click on the optgroup header, I get its location (the name appears in the drop-down list). Then I look through all the parameters in the table # select2 and find which of them contain this location in my html.

I know this is a hacky workaround, but hopefully it helps / points in the right direction.

+1
source share

John S, provided that the example works very well (for V3) for most cases. However, he has one error:

Assuming the selection list is long enough to have a scroll. When you select any item in any group that is only available after scrolling down, you cannot select the next item after the one you selected from this group. This is because the secureHighlightVisible select2 method starts erroneously because the selector that it uses is made using the assumption that the group is always "non-selectable." That way, the scroll will jump every time you try to select an item.

So, unfortunately, although this solution looks very good - I dropped it and re-executed it without using group identifiers:

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

and

  // 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"); } } 
0
source share

Well, I came across this problem, and I found that every time select2 (Select2 4.0.5) is opened, it adds a span element in front of the closing body element. In addition, ul with the identifier is added inside the span element: select2-X-results, where X is the identifier of select2. So I found the following workaround ( 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> 
0
source share

I found a plugin for Select2 v4 that adds the ability to click on optgroup to select / deselect all child parameters. This worked great for me. bnjmnhndrsn / Selection 2-OPTGROUP-select

Thanks Ben Henderson!

0
source share

All Articles