When using jquery select2 plugin, how can I prevent new tags from being chosen if there is a valid value from the ajax call already listed? When using jquery select2 plugin, how can I prevent new tags from being chosen if there is a valid value from the ajax call already listed? ajax ajax

When using jquery select2 plugin, how can I prevent new tags from being chosen if there is a valid value from the ajax call already listed?


According to Select2 Options

Change how options are matched when searching When users filter down the results by entering search terms into the search box, Select2 uses an internal "matcher" to match search terms to results. When a remote data set is used, Select2 expects that the returned results have already been filtered.

Key matcher Value A function taking search params and the data object. Select2 will pass the individual data objects that have been passed back from the data adapter into the matcher individually to determine if they should be displayed. Only the first-level objects will be passed in, so if you are working with nested data, you need to match those individually.

matcher: function (params, data) {  // If there are no search terms, return all of the data  if ($.trim(params.term) === '') {    return data;  }  // `params.term` should be the term that is used for searching  // `data.text` is the text that is displayed for the data object  if (data.text.indexOf(params.term) > -1) {    var modifiedData = $.extend({}, data, true);    modifiedData.text += ' (matched)';    // You can return modified objects from here    // This includes matching the `children` how you want in nested data sets    return modifiedData;  }  // Return `null` if the term should not be displayed  return null;}

I think this is your typical case ,except that you should replace ("matched") with ("") , and add else to add that "[NEW]" in your case.

The returned data from ajax call should be the input to your matcher.

so your code should look like:

  matcher: function (params, data) {  // If there are no search terms, return all of the data  if ($.trim(params.term) === '') {    return data;  }  // `params.term` should be the term that is used for searching  // `data.text` is the text that is displayed for the data object  if (data.text.indexOf(params.term) > -1) {    var modifiedData = $.extend({}, data, true);   //match was found then just show it.   // modifiedData.text += ' (matched)';    // You can return modified objects from here    // This includes matching the `children` how you want in nested data sets    return modifiedData;  }   else  {   //there is not match found , suggest adding NEW Tag.    modifiedData.text += '[NEW]';    return modifiedData;  }  // Return `null` if the term should not be displayed  return null;}


Please correct me if I have misunderstood your question. But as per my understanding I have come up with following solution.

For demo purpose I have pre-loaded couple of <option> elements within <select> box and instead of ajax data feed to select2 I am using plain JavaScript array object mimicking ajax response.

The Updated fiddle link: https://jsfiddle.net/vijayP/akyzt9Ld/11/

The HTML is as follows:

<div id="tagsContainer">    <select id="Tags" multiple="" name="Tags">       <option value="white">white</option>       <option value="green">green</option>    </select></div> 

Here we can see that, the last <option> present in dropdown has text green.

JSON data object which mimic ajax response looks like below:

var data = [{ id: 0, name:'yellow', text: 'yellow' },                 { id: 1, name:'green', text: 'green' },                 { id: 2, name:'cyan', text: 'cyan' },                 { id: 3, name:'violet', text: 'violet' },                 { id: 4, name:'gray', text: 'gray' }                ];

Here again the green is at number 2.

select2 initialization and supporting JavaScript code goes like this:

    var uniqueTexts = null; //array for holding unique text    $("#Tags").select2({        tags: true,        data: data,        templateResult: tagFormatResult,        escapeMarkup: function (markup) {             uniqueTexts = null;             return markup;         },         matcher: function (params, data) {            if(!uniqueTexts){                uniqueTexts = [];             }            var modifiedData = null;            if ($.trim(params.term) === '' || data.text.indexOf(params.term) > -1) {                if(uniqueTexts.indexOf(data.text) == -1)                {                    modifiedData = data;                    uniqueTexts.push(modifiedData.text);                }            }            if(modifiedData)            {                return modifiedData;            }            return null;        }    });    function tagFormatResult(tag) {        if (tag.loading) {            return "Loading . . . <img src='/Content/Images/ajax-loader.gif' />";        }         else         {            var length = $('#tagsContainer .select2-selection__choice').filter(function () {                return $(this).attr("title").toUpperCase() === tag.text.toUpperCase();            }).length;            if (length == 1) {                return tag.text;            }            if (tag.text) {                if(getOptionCount(tag.text) >1)                    return tag.text;                else                    return tag.text + " [NEW]";            }            return tag.text + " [NEW]";        }    }    function getOptionCount(tagText)    {        var count = 0;        var selectBoxOptions = $("#Tags option");        $(selectBoxOptions).each(function(){            if(tagText == $(this).text())                count++;//increment the counter if option text is matching with tag text        });        return count;    }

var uniqueTexts is an array to hold unique text to be shown to the end user. While initiating we are setting it to null. So the idea is whenever user focus-in to the select box OR type-in search keyword; matcher: callback gets called for each option. We check each option and see if it is already present in uniqueTexts[] or not. If its a first occurrence then we allow it to show; otherwise we return null to avoid it from showing 2nd time.

I also added a escapeMarkup: callback handler which gets called whenever options are shown to the end user. This is the point when we can again set uniqueTexts to null. This is the complete one round of cycle. Again user can focus-in or type-in to select box.

function tagFormatResult(tag) works as follows:

1) First it checks whether current tag is already been selected or not. If it is already selected then don't add "[NEW]" text to tag.text

2) Secondly it checks whether current tag.text is present as select option text more than once or not. If it is present at more than one places, then also don't add "[NEW]" to tag.text.

3) In all other cases go ahead and add "[NEW]" to tag.text.

I hope this will help you a bit.Updated Link: https://jsfiddle.net/vijayP/akyzt9Ld/11/