Select2 с createSearchChoice использует вновь созданный выбор для ввода с клавиатуры, даже если есть совпадение, ошибка или я что-то упустил?

Я использую Select2 (версия 3.4.0) для заполнения списка тегов. Теги сопоставляются с существующими с помощью вызова ajax, и я использую createSearchChoice, чтобы разрешить создание новых тегов. Код работает до сих пор и выглядит примерно так:

$(mytags).select2({
    multiple: true,
    placeholder: "Please enter tags",
    tokenSeparators: [ "," ],
    ajax: {
        multiple: true,
        url: myurl,
        dataType: "json",
        data: function(term, page) {
            return {
                q: term
            };
        },
        results: function(data, page) {
            return data;
        }
    },
    createSearchChoice: function(term) {
        return {
            id: term,
            text: term + ' (new)'
        };
    },
});

Все довольно стандартно, за исключением добавления (new) в createSearchChoice. Мне нужно, чтобы пользователи знали, что это не существующий ранее тег.

Это работает так, как ожидалось: если я начну вводить «новый тег», я получу тег «новый тег (новый)», предложенный вверху списка, и если я выберу его, список тегов будет содержать «новый тег (новый)». )", как и ожидалось. Если тег уже существует, Select2 обнаруживает совпадение, и «(новый)» выбор не создается. Нажатие возврата или нажатие на совпадение работает должным образом.

Проблема возникает, когда я набираю запятую (моя единственная запись tokenSeparators), когда есть совпадение. Select2 закрывает этот токен и добавляет тег в список, но с добавленной меткой «(новый)», т.е. он использует возвращаемое значение из createSeachChoice, даже если это не обязательно.

Это ошибка в Select2, или я неправильно ее использую (и что мне делать вместо этого)?


person Ben Deutsch    schedule 17.05.2013    source источник


Ответы (3)


Я не уверен, является ли это ошибкой или нет — в любом случае, в настоящее время нет открытой проблемы, связанной с этим поведением, в системе отслеживания проблем GitHub.

Однако вы можете исправить поведение самостоятельно. Идея состоит в том, что обратный вызов createSearchChoice должен быть в состоянии сказать, относится ли term к результату поиска или нет. Но createSearchChoice не имеет прямого доступа к результатам поиска, так как же мы можем его включить? Что ж, сохранив последнюю партию результатов поиска внутри обратного вызова results.

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)" };
        }
    }
});

В этом коде используется Array.some, поэтому вам нужно нечто лучшее, чем IE8 ( что является минимальным требованием select2) для его запуска, но, конечно, можно эмулировать поведение.

Посмотрите на это в действии.

Однако есть и ложка дегтя: этот код работает корректно, только если результаты поиска, соответствующие текущему поисковому запросу, уже получены.

Это должно быть очевидно: если вы печатаете очень быстро и создаете условие поиска, которое соответствует существующему тегу, но нажимаете запятую до того, как будут получены результаты поиска, содержащие этот тег, createSearchChoice будет проверять наличие тега среди ранее полученных результатов поиска. Если эти результаты не содержат тег, тег будет отображаться как «новый», даже если это не так.

К сожалению, я не верю, что вы можете что-то сделать, чтобы предотвратить это.

person Jon    schedule 31.05.2013
comment
Спасибо, в моем случае результаты должны быть достаточно быстро, и пока это работает в большинстве случаев, этого должно быть достаточно. - person Ben Deutsch; 02.06.2013
comment
Отличный ответ Джон. Я заметил, что в вашей скрипке, если вы введете bar и нажмете Enter на клавиатуре, будет выбран foo, что, я думаю, не является желаемым поведением. - person Marklar; 22.01.2014
comment
Поскольку этот ответ был написан, для этого в GitHub была добавлена ​​проблема: github.com/ivaynberg/select2 /вопросы/794. У меня есть базовая реализация предложения, которое там работает, и, вероятно, скоро отправлю запрос на вытягивание (я прокомментирую приведенную выше ссылку, когда сделаю это). - person Matt Browne; 14.02.2014
comment
Это отличный ответ! Я заметил (и, может быть, я просто использую более новую версию), что вам не нужно хранить в этом lastResults. Если вы выполните функцию createSearchChoice: (термин, данные), то данные будут содержать то, что вам нужно, как и lastResults. Спасибо за помощь - person jacklin; 07.03.2014
comment
@jacklin: Я немного покопался в источнике и пришел со смешанными чувствами: с одной стороны, это работает именно так, как вы говорите. OTOH, createSearchChoice также вызывается по умолчанию < href="http://ivaynberg.github.io/select2/index.html#doc-tokenizer" rel="nofollow noreferrer">токенизатор с текущим выбором в качестве второго аргумента. Так что, к сожалению, я не думаю, что мы можем безоговорочно рекламировать это как решение, как бы это ни было хорошо (кроме того, этот аргумент не задокументирован - это специально или ошибка документации?). - person Jon; 10.03.2014
comment
не могли бы вы предложить мне какую-либо документацию, связанную с этим createSearchChoice, или любую связанную ссылку на быстрый просмотр. Благодарю вас. - person ankit suthar; 14.06.2017

Вместо того, чтобы подправлять результат, я думаю, лучше работать на стороне сервера.

Если сервер не находит тег, он возвращает ответ json с новым тегом.

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

У 'createSearchChoice' есть еще один параметр - 'page', он перечисляет все варианты, с его помощью легко найти дубликаты.

createSearchChoice = function (term, page) {
    if( page.some(function(item) {
        return item.text.toLowerCase() === term.toLowerCase();
    }) ){
        return { val: term, name: term + '*' };
    }
}
person Tom    schedule 16.10.2014