Selectable optgroup using select2
I've 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 query 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 });
}
This is possible if you back the Select2 with a hidden input element -- instead of a select element.
To make a group option selectable, you must give it an "id", but it appears it can be an empty string. You can then use the "select2-selecting" event to prevent the group option from getting selected, and instead have its child options get selected.
Additionally, a query
function can be provided to prevent a group option from appearing in the list after all its child options have been selected.
If you have options defined like this:
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 instrument your Select2 like this:
$('#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 a jsfiddle without the query
function, where the group options still appear when all of their child options are selected.
I found a plugin for Select2 v4 which adds the ability to click on the optgroup to select/unselect all of child options. It worked perfectly for me. bnjmnhndrsn/select2-optgroup-select
Thanks Ben Henderson!
First give id to your select for example
<select style="width: 95%" id="selectgroup">
and then add class to your optgroup like
<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 the optgroup.