How to hide selected item when searching

I have one select2 option

As example:
enhancement & invalid have been selected
when searching, the ‘invalid’ still appear on search result.

image

I want to hide enhancement & invalid when searching, please help and thank you

You can supply a templateRender function to control which items are displayed in the dropdown. In your function, you can call the .select2('data') method on your <select> element to get an array of the currently selected items, which you would then compare to the current item passed to your templateRender function. If the current item is in the list of current selections, you would return null to prevent that item from being displayed; otherwise you would return the current item’s text property to display it in the dropdown.

I want to hide the selected item only when searching and in the dropdown still shown

In that case, you can use a custom matcher function instead of a templateResult function. The matcher function is only called when the user is typing and the dropdown is shown, not when the dropdown is simply opened without the user typing anything.

Your matcher function gets two parameters each time it’s called (once for each item in the dropdown): a params object whose term property contains the current search term, and a data object that represents an item in the dropdown. Your function would have to return the data object passed to it unless that object represents one of the selected items; in that case your function would return null, which would prevent that item from being displayed. Note that your matcher function probably also needs to return null for any data object that does not match the user’s current search term.

do you mind to write an example?

Something like this should work:

function hideSelectedAndMatched(params, item) {
  const currentSelections = $('#mySelect').select2('data');
  // Exclude the item if it matches one of the current selections.
  if (currentSelections.find(selection => return selection.id === item.id)) {
    return null;
  }
  // If no search term, or the item matches the search term, return the item.
  if (!params.term || params.term.trim() === '' 
      || item.text.indexOf(params.term) > -1) {
    return item;
  }
  // The item doesn't match the search term, so exclude it.
  return null;
}

// Initialize Select2 widget with custom matcher:
$('#mySelect').select2({
  // ... some configuration options
  matcher: hideSelectedAndMatched,
  // ... some more configuration options
});

Is there a way to find the current selections if this is a generic matcher where you could not include the selector in the function?

const currentSelections = $(’#mySelect’).select2(‘data’);

I don’t understand what you mean by “a generic matcher where you could not include the selector in the function”. Have you created a custom matcher, or are you using the built-in one? If it’s custom, can you paste your code here? If it’s the built-in matcher, then the code you posted is the documented way to get the current selections.

It is a custom matcher which does exactly what your example matcher does and removes existing selections from the dropdown list. The difficulty I am having is I want the custom matcher to be used by multiple select2 instances. I was looking for a way to be able to tell which select2 instance the matcher was attached to and therefore be able to calculate the selector. Within your matcher it is hardcoded to one instance. Thanks for your quick reply.

Yeah, there’s no way to tell (natively). If you’re using a JavaScript array or AJAX to provide data to your Select2’s, you could include a custom field in each data item that would indicate which Select2 the data item belongs to, and that custom field would be available to the matcher.

Instead, you could create a function that returns your custom matcher function, and that “matcher-maker” function takes a parameter whose value gets “baked” into the returned matcher (i.e., the returned matcher function is a closure over the parameter’s value). You would use this extra parameter to identify which Select2 the matcher is assigned to. You’d just have to pass that identifying value when you initialize your Select2s. One way to do that would be to assign a unique id value to each <select> and then pass that ID value to the “matcher-maker” in the select2() initialization call:

function makeMatcher(selectId) {
  return function(params, item) {
    // ... matcher code goes here. The logic that needs to reference the owning 
    //     Select2 can reference the `selectId` value, which will be "baked in" to 
    //     this instance of the matcher function.
};

$(`.select2`).each(function(index, selectElt) {
  $(selectElt).select2({
    ...
    matcher: makeMatcher(selectElt.attr('id')),
    ...
});

Does that make sense?

It does - thanks. I was just hoping there was a way to do it natively.