With select2 jquery plugin with tags:true, how can you prevent choices from showing up in the dropdown that are already selected?
Asked Answered
K

3

10

I am migrating over to select2 to use as a tagging plugin from another plugin but there is one gap that I am trying to figure out if select2 can support.

Let look at an example. Lets say my list of choices (coming back server side from Ajax request) is

"Dog", "Cat", "Monkey", "Giraffe"

In the old plugin I am using, after I choose one of the choices (lets say "Cat") and it shows up in the textbox, the next time I search for the same partial string (lets say "Ca"), it DOESN"T have "Cat" show up in the dropdown of choices (as it know that you have already chosen it previously)

It seems like select2 still shows the item in the dropdown when searching regardless if you have selected it already. Select2 does prevent entering if after you hit enter but this seems a bit unintuitive so I am trying to figure out if there is a way for select2 to replicate that same behavior from the other plugin (where the choices don't even show up)

As another example of this working properly, the stackoverflow tag section of a question also does the right thing. If I add "jquery" to my list of tags for this question and then search for "jquery" again, it DOESN"T show that in the list (as its already been chosen). That is the behavior that I am looking for.

Here is my current select2 code:

HTML:

<select id="Tags" name="Tags" multiple="multiple">
</select>

Javascript:

function SetupAppTags() {
$("#Tags").select2({
    theme: "classic",
    width: "98%",
    tags: true,
    ajax: {
        url: "/Tag/Search",
        dataType: 'json',
        delay: 300,
        data: function(params) {
            return { q: params.term };
        },
        processResults: function(data, params) {
            return { results: data };
        },
        cache: false
    },
    escapeMarkup: function(markup) { return markup; },
    minimumInputLength: 3,
    templateResult: tagFormatResult,
    templateSelection: tagSelectionResult
});
}

function tagFormatResult(tag) {

   if (tag.loading) {
    return "Loading . . .";
} else {
    if (tag.name) {
        return tag.name;
    }
    return tag.text + " [NEW]";
}
}

function tagSelectionResult(tag) {
    if (tag.name) {
     return tag.name;
  }
   return tag.text;
}

I would think that somehow in the templateResult function there is a way to return false or something to not show that item if its already selected. Is something like this possible (can't find anything online or in the docs)

Kaspar answered 26/9, 2015 at 13:22 Comment(0)
W
5

It sounds like you're looking for a custom matcher. Using one will allow you to filter the dropdown items before displaying it to the user.

var $t = $('#target');
$t.select2({
  multiple: true,
  tags: true,
  data: ["Pasty", "Pasta", "Posters"],
  matcher: function(params, option) {
    var selected = $t.select2('data');
    var optionSelected = selected.some(function(item) {
      return (item.text === option.text);
    });
    if (optionSelected) return false;
    return option;
  }
});
#target {
  width: 100%;
}
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.min.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.min.css" rel="stylesheet" />
<select id="target"></select>
Williams answered 3/10, 2015 at 15:31 Comment(2)
do you know what the difference between a custom matcher versus returning null in the templateResult function?Kaspar
@Kaspar I looked through the docs and did some debugging, both are feasible options as they offer somewhat duplicate functionality. From the docs: "[Select2 uses the] matcher to determine if [each result] should be displayed." "The templateResult can also return null, which will prevent the option from being displayed in the results list." So as you can see, they allow the user to do the same thing via different routes. Why the library was designed like this is not too clear, but the reason is probably ease of use if you only want to change one or the other in minor details.Williams
I
0

You should look at changing the templateResult function...

The templateResult function should return a string containing the text to be displayed, or an object (such as a jQuery object) that contains the data that should be displayed. It can also return null, which will prevent the option from being displayed in the results list.

https://select2.github.io/options.html#templateSelection

Inclose answered 26/9, 2015 at 13:30 Comment(3)
thanks James. I have updated ytour answer with the solution that seems to work. Please let me know if you see any issues with my solution or have another suggestionKaspar
Actually, I just realized the above answer I added to your question DOESN"T work as if you remove a tag it still shows up in the list so you get an issue where if you remove a tag and want to add it back in, it doesn't allow you to .. So I am back to the drawing board. Do you know how I can prevent ?Kaspar
sorry I don't :( I have never used that before but from reading the documentation it looked like it would workInclose
R
-1

You can achieve this simply like below,

You need to hide the selected options using CSS

$('select').select2();
.select2-container--default .select2-results__option[aria-selected=true] {
    display: none;
}
<link href="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.min.js"></script>

<select id="Tags" name="Tags" multiple="multiple">
  <option value="1">first</option>
  <option value="2">second</option>
  <option value="3">third</option>
  <option value="4">fourth</option>
</select>
Rovner answered 3/10, 2015 at 14:56 Comment(2)
It's a trick that works, but it may causes another problems, like keyboard selection.Skilled
Hey, don't worry, I make it in a project and it works, but in other situations I can't write this trick. Depending on the needs of the OP. Good luck!Skilled

© 2022 - 2024 — McMap. All rights reserved.