I'm using select2 with Bootstrap 3. Now I would like to know whether it is possible to display all optgroup items if the search matches the optgroup name while still being able to search for items as well. If this is possible, how can I do it?
Display result matching optgroup using select2
Asked Answered
Actually found the solution by modifying the matcher opt
$("#myselect").select2({
matcher: function(term, text, opt){
return text.toUpperCase().indexOf(term.toUpperCase())>=0 || opt.parent("optgroup").attr("label").toUpperCase().indexOf(term.toUpperCase())>=0
}
});
Under the premise that the label attribute has been set in each optgroup.
text.toUpperCase is not a function error. Debugged and saw that text comes as object, not string? Have you seen this problem? –
Bubbly
No not seen. What kind of object is that? Do you have a dump of the object? Perhabs with newer version the matcher params have been changed? –
Assurgent
Select2 V4 passes different params to the matcher function. (See answer from @willbradley) Maybe that could help you –
Assurgent
The above answers don't seem to work out of the box with Select2 4.0 so if you're hunting for that, check this out: https://github.com/select2/select2/issues/3034
(Use the function like this: $("#example").select2({matcher: modelMatcher});
)
function modelMatcher (params, data) {
data.parentText = data.parentText || "";
// Always return the object if there is nothing to compare
if ($.trim(params.term) === '') {
return data;
}
// Do a recursive check for options with children
if (data.children && data.children.length > 0) {
// Clone the data object if there are children
// This is required as we modify the object to remove any non-matches
var match = $.extend(true, {}, data);
// Check each child of the option
for (var c = data.children.length - 1; c >= 0; c--) {
var child = data.children[c];
child.parentText += data.parentText + " " + data.text;
var matches = modelMatcher(params, child);
// If there wasn't a match, remove the object in the array
if (matches == null) {
match.children.splice(c, 1);
}
}
// If any children matched, return the new object
if (match.children.length > 0) {
return match;
}
// If there were no matching children, check just the plain object
return modelMatcher(params, match);
}
// If the typed-in term matches the text of this term, or the text from any
// parent term, then it's a match.
var original = (data.parentText + ' ' + data.text).toUpperCase();
var term = params.term.toUpperCase();
// Check if the text contains the term
if (original.indexOf(term) > -1) {
return data;
}
// If it doesn't contain the term, don't return anything
return null;
}
this worked. this should now be the answer, as the above indeed have issues. thanks willbradley. –
Dubiety
Actually found the solution by modifying the matcher opt
$("#myselect").select2({
matcher: function(term, text, opt){
return text.toUpperCase().indexOf(term.toUpperCase())>=0 || opt.parent("optgroup").attr("label").toUpperCase().indexOf(term.toUpperCase())>=0
}
});
Under the premise that the label attribute has been set in each optgroup.
Nice! I recommend using the default matcher implementation, though, unless you intentionally want to deviate from the default matcher.
element.select2({ matcher: function (term, text, opt) { return element.select2.defaults.matcher(term, text) || element.select2.defaults.matcher(term, opt.parent("optgroup").attr("label")); } });
This allows for slightly better matching by not only ignoring case, but also ignoring diacritics. –
Fredette text.toUpperCase is not a function error. Debugged and saw that text comes as object, not string? Have you seen this problem? –
Bubbly
No not seen. What kind of object is that? Do you have a dump of the object? Perhabs with newer version the matcher params have been changed? –
Assurgent
Select2 V4 passes different params to the matcher function. (See answer from @willbradley) Maybe that could help you –
Assurgent
Found a solution from select2/issues/3034
Tested with select2 v.4
$("select").select2({
matcher(params, data) {
const originalMatcher = $.fn.select2.defaults.defaults.matcher;
const result = originalMatcher(params, data);
if (
result &&
data.children &&
result.children &&
data.children.length
) {
if (
data.children.length !== result.children.length &&
data.text.toLowerCase().includes(params.term.toLowerCase())
) {
result.children = data.children;
}
return result;
}
return null;
},
});
A few minor changes to people suggested code, less repetitive and copes when there are no parent optgroups:
$('select').select2({
matcher: function(term, text, opt){
var matcher = opt.parent('select').select2.defaults.matcher;
return matcher(term, text) || (opt.parent('optgroup').length && matcher(term, opt.parent('optgroup').attr("label")));
}
});
© 2022 - 2024 — McMap. All rights reserved.
element.select2({ matcher: function (term, text, opt) { return element.select2.defaults.matcher(term, text) || element.select2.defaults.matcher(term, opt.parent("optgroup").attr("label")); } });
This allows for slightly better matching by not only ignoring case, but also ignoring diacritics. – Fredette