What I gather from your question is you want to be able to show option
s for selection when there's a match in either the option
text OR the option
's parent optgroup
value attribute.
This is relatively straightforward: Mainly, look at both of the values and if either matches, return true
using Select2's matcher
option:
(Note: Using Select2 v3.5.4.)
(function() {
function matcher(term, text, opt) {
var $option = $(opt),
$optgroup = $option.parent('optgroup'),
label = $optgroup.attr('label');
term = term.toUpperCase();
text = text.toUpperCase();
if (text.indexOf(term) > -1
|| (label !== undefined
&& label.toUpperCase().indexOf(term) > -1)) {
return true;
}
return false;
}
$(".select2").select2({
matcher: matcher
});
})();
https://jsfiddle.net/xfw4tmbx/2/
v4.* and above changed the term
and text
to a more complex object, so it'll be slightly different, but the main concept is the same. As you can see, all I'm doing is using jQuery to select up to the option
's parent if it's an optgroup
element and including that in the matcher
check.
Also, an optgroup
will display if any of it's children are shown, so you only have to worry about displaying one or more of the option
's, and not actually "show" the optgroup
by manually showing it.
If you have a different requirement, please provide a (working/non-working?) demonstration fiddle showing what you have where we can actually run it.
EDIT
Select2 custom matching changed significantly with the 4.0 release. Here is a custom matcher that was posted to this GitHub issue. It is reproduced as-is below for completeness.
Notice that it's calling itself for child elements (the option
elements within the optgroup
elements), so modelMatcher()
is running against both the optgroup
and the option
elements, but the combined set is returned after removing the optgroup
and option
elements that don't match. In the version above, you got every option
element and simply returned true/false if you wanted it (and the parent) displayed. Not that much more complicated, but you do have to think about it a little bit more.
(function() {
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;
}
$(".select2").select2({
matcher: modelMatcher
});
})();
https://jsfiddle.net/xfw4tmbx/16/
data.indexOf
in Select2. Are you sure it's Select2 that's erroring? – Zoophyte