Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Display result matching optgroup using select2

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?

like image 226
Nirmi Avatar asked Feb 24 '14 16:02

Nirmi


3 Answers

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;
    },
});
like image 102
ikhvjs Avatar answered Nov 18 '22 00:11

ikhvjs


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;
}
like image 33
willbradley Avatar answered Nov 18 '22 00:11

willbradley


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.

like image 21
Nirmi Avatar answered Nov 18 '22 00:11

Nirmi