Программно добавить новую опцию jquery-select2-4 и reset в поле поиска?

Я использую jquery-select2-4 для поиска внешней базы данных и предоставления пользователю результатов поиска, которые он может выбрать.

У меня рабочая версия, работающая на этом jsfiddle.

Но если, например, возвращается только 1 результат поиска, я хочу пропустить весь процесс выбора и просто добавить возвращаемый результат поиска в список выбранных параметров. В соответствии с select2 docs я могу добавить новый вариант:

option = new Option("Sample text", "123", true, true);
select2_element.append(option);
select2_element.trigger('change');

Это, похоже, работает в некоторой степени. Но есть несколько проблем.

  • Я не могу очистить поле поиска при добавлении опции.
  • Я не могу добавить ничего, что id и text.
  • Добавленная опция отображается пользователю как undefined.

Я понимаю, что этот вопрос содержит 3 грани, но все 3 грани, вероятно, обращаются к этому 1 вопросу:

Как вы программно добавляете новый параметр jquery-select2-4 и reset в поле поиска?

Для вашей справки это контекст кода, о котором я спрашиваю:

var formatRepo, formatRepoSelection, selectRepos;

formatRepoSelection = function(element) {
  return element.name + ' ' + element.forks + ' ' + element.id;
};

formatRepo = function(element) {
  var markup;
  if (!element.loading) {
    return markup = element.name + ' ' + element.id;
  }
};

selectRepos = function() {
  var option, select2_element;
  select2_element = $('#select2_element');
  select2_element.select2({
    ajax: {
      url: "https://api.github.com/search/repositories",
      dataType: 'json',
      data: function (params) {
        return {
          q: params.term,
          page: params.page
        };
      },
      processResults: function (data, params) {

        if (data.items.length === 1) {
          // START: The code I am asking about.
          // Add the search result directly as an option.
          option = new Option("Sample text", "123", true, true);
          select2_element.append(option);
          return select2_element.trigger('change');
          // END: The code I am asking about.
        } else {
          params.page = params.page || 1;

          return {
            results: data.items,
            pagination: {
              more: (params.page * 30) < data.total_count
            }
          };
        }
      },
      cache: true
    },

    escapeMarkup: function(markup) {
      return markup;
    },
    templateResult: formatRepo,
    templateSelection: formatRepoSelection
  });
};

$(function() {
  return selectRepos();
});

Ответ 1

Я сделал два изменения исходного кода:

1. Имитировать выбор только оставшегося элемента

Как вы указали, создание элемента option имеет свои ограничения: вы можете указывать только свойства id и text, не оставляя возможности иметь доступ к выбранным элементам других свойств.

Кроме того, он генерирует значения undefined. Это связано с тем, что функция обратного вызова formatRepoSelection пытается получить доступ к свойствам (имя и вилки), которые undefined для объекта, созданного для элемента option. Вы могли бы попытаться обойти это и использовать свойство text в этом случае, но все же у вас не было бы решения для вышеуказанных ограничений.

Предлагаемое мной решение имеет другой подход. Вместо того, чтобы создавать тег напрямую, вы можете имитировать пользовательский выбор этого последнего элемента, отправив событие mouseup в этот элемент списка.

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

  • текст фильтра очищается автоматически;
  • функция formatRepoSelection получает обычный объект, поэтому метка тега, как и ожидалось,
  • Те же свойства доступны для вас как для любого элемента.

Вот код, реализующий это:

    if (data.items.length === 1) {
      // Change 1:
      // Allow the list to update
      setTimeout(function() {
          // ... and then send a click event to the first list item
          // Note the used id has the SELECT id in the middle.
          $("#select2-select2_element-results li:first-child").trigger('mouseup');
      }, 0);

Недостатком этого решения является то, что вы зависите от аспекта реализации; будущая версия select2 может упорядочить результаты по-разному с точки зрения HTML-элементов и свойств.

Но это не должно быть большой проблемой для обновления кода, когда вы решите перейти с более новой версией select2.

2. Вернуть правильный объект

Ваш код сгенерировал ошибку в библиотеке select2:

TypeError: b - undefined, на select2.min.js: 2: 9842

Это из-за этого утверждения:

return select2_element.trigger('change');

Это возвращает объект jQuery select2_element, но библиотека ожидает, что возвращаемое значение будет иметь свойство результатов.

Поскольку этот триггер больше не нужен, это можно устранить, заменив выше:

  // Change 2:
  // Return empty results array
  return {
    results: data.items
  };

Не поддавайтесь соблазну установить results: [], потому что нам все еще нужен элемент для имитации события мыши с помощью.

И... это все.

Вот рабочее решение: JS скрипка.