Select2 with createSearchChoice uses newly created choice for keyboard entry even given a match, bug or am I missing something?

那年仲夏 提交于 2019-11-28 23:21:15
Jon

I 'm not sure if this is a bug or not -- in any case, there is no open issue referring to this behavior at the GitHub issue tracker at this moment.

You can mostly fix the behavior yourself though. The idea is that the createSearchChoice callback must be able to tell if term refers to a search result or not. But createSearchChoice does not have direct access to the search results, so how can we enable that? Well, by saving the latest batch of search results from inside the results callback.

var lastResults = [];

$(...).select2({
    ajax: {
        multiple: true,
        url: "/echo/json/",
        dataType: "json",
        type: "POST",
        data: function (term, page) {
            return {
                json: JSON.stringify({results: [{id: "foo", text:"foo"},{id:"bar", text:"bar"}]}),
                q: term
            };
        },
        results: function (data, page) {
            lastResults = data.results;
            return data;
        }
    },
    createSearchChoice: function (term) {
        if(lastResults.some(function(r) { return r.text == term })) {
            return { id: term, text: term };
        }
        else {
            return { id: term, text: term + " (new)" };
        }
    }
});

This code uses Array.some so you need something better than IE8 (which is the select2 minimum requirement) to run it, but of course it is possible to emulate the behavior.

See it in action.

There is, however, a fly in the ointment: this code works correctly only if the search results corresponding to the current search term have been already received.

This should be obvious: if you type very fast and create a search term that corresponds to an existing tag but hit comma before the search results that include that tag have arrived, createSearchChoice will be testing for the tag's presence among the previously received search results. If those results do not include the tag, then the tag will be displayed as "new" even though it is not.

Unfortunately I don't believe there is anything you can do to prevent this from happening.

Instead of tweeking the result, I think it is better to work on the server side.

If the server doesn't find a tag make it return a json answer with the new tag

{"more":false,"results":[{"id":"whatever","text":"new-tag (new)"}]}

There is another parameter for the 'createSearchChoice' - 'page', it lists all the choices, you can easily find dupes with it.

createSearchChoice = function (term, page) {
    if( page.some(function(item) {
        return item.text.toLowerCase() === term.toLowerCase();
    }) ){
        return { val: term, name: term + '*' };
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!