1
votes

I'm trying to allow only one value within select2 library, no matter how it's written. For example if the value "Test" is in the data list, "test" should not be added again. I've searched for a while and also looked at the documentation, but I didn't solve this one.

        $("#timezones").select2({
            tags: true,
            createTag: function (tag) {
                return {
                    id: tag.term,
                    text: tag.term + " (new)",
                    isNew: true
                };
            },
            matcher: function (term, data) {
                // `term.term` should be the term that is used for searching
                // `data.text` is the text that is displayed for the data object
                if ($.trim(term.term) === '') {
                    return data;
                }

                var termString = term.term.trim();
                var textString = data.text.trim();
                var termStringUpper;
                var textStringUpper;

                if (termString) termStringUpper = termString.toUpperCase();
                if (textString) textStringUpper = textString.toUpperCase();

                return termStringUpper == textStringUpper;
            }
        });

Here is one JSFiddle: https://jsfiddle.net/2sz0oj8m/

2

2 Answers

4
votes

The issue is that you are running all the comparisons in the matcher method when you should be running them in the createTag method:

  • By default, matcher is case insensitive and you don't need to ran any special code for that. Notice that if you remove the function, and type "test", the suggestions will include "Test" (with a capital T even when you wrote it with a lower case t).

  • createTag specifies the actions that will be run to suggest a new tag creation. It is executed with each change in the textbox (as specified here) and not when there is not a match.

So the solution would be to:

  1. Remove the matcher method.
  2. Add the case comparison to the createTag method.
  3. Only return the new suggestion if no case-insensitive match was found.

The result would be like this:

$("#timezones").select2({
    tags: true,
    createTag: function (tag) {

        // Check if the option is already there
        var found = false;
        $("#timezones option").each(function() {
            if ($.trim(tag.term).toUpperCase() === $.trim($(this).text()).toUpperCase()) {
                found = true;
            }
        });

        // Show the suggestion only if a match was not found
        if (!found) {
            return {
                id: tag.term,
                text: tag.term + " (new)",
                isNew: true
            };
        }
    }
});

And you can see it running on this update of your JSFiddle: https://jsfiddle.net/2sz0oj8m/1/ (type "test" and you'll see how the suggestion doesn't show up for that particular value).

EDIT: This solution is not compatible with remote data source, you may want to store last values or directly check in ajax results if tag is existing.

1
votes

For remote data source and tags:true, I did the following code:

$('selector').select2({
    tags: true,
    createTag: function ($params) {
        var $term = $.trim($params.term);
        if ($term === '') {
          return null;
        }

        return {
          id: $term,
          text: $term,
          newTag: true // add additional parameters
        }
    },
    insertTag: function(data, tag) {
        var $found = false;
        $.each(data, function(index, value) {
            if($.trim(tag.text).toUpperCase() == $.trim(value.text).toUpperCase()) {
                $found = true;
            }
        });

        if(!$found) data.unshift(tag);
    },
    // .. other select2 options include remote options 
});
  • Note: The code above is for Select2 4.0.x