Select2 - Сортировка результатов по запросу

Я использую Select2 version 4.0.0.

Если мои результаты содержат несколько слов, и пользователь вводит одно из этих слов, я хотите отобразить результаты, отсортированные по тому, где введенное слово находится в результате.

Например, пользователь вводит "яблоко", и мои результаты:

  • "банановое апельсиновое яблоко"
  • "банановый яблочный апельсин"
  • "яблочный банановый апельсин"

Затем "яблочный банановый апельсин" должен появиться сначала в списке результатов select2, потому что это результат, в котором "яблоко" появляется в самом начале в результате. Мне все равно, о том, как это сделать.

Что я могу переопределить или настроить, чтобы получить что-то вроде этого? Кажется, что matcher не упорядочивание порядка, а sorter не содержит данных запроса.

Ответ 1

Вы можете захватить поисковый запрос из значения поля ввода, сгенерированного Select2, путем идентификации его с классом select2-search__field. Вероятно, это приведет к разрыву версий, но поскольку они не обеспечивают крючок для получения запроса, потребуется какой-то хак. Вы можете отправить вопрос, чтобы они добавили поддержку для доступа к запросу во время сортировки, тем более, что это похоже на возможность выбора в Select2 3.5.2.

$('#fruit').select2({
  width: '200px',
  sorter: function(results) {
    var query = $('.select2-search__field').val().toLowerCase();
    return results.sort(function(a, b) {
      return a.text.toLowerCase().indexOf(query) -
        b.text.toLowerCase().indexOf(query);
    });
  }
});
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.min.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.min.css" rel="stylesheet" />

<select id="fruit">
  <option>Banana Orange Apple</option>
  <option>Banana Apple Orange</option>
  <option>Apple Banana Orange</option>
  <option>Achocha Apple Apricot</option>
  <option>Durian Mango Papaya</option>
  <option>Papaya</option>
  <option>Tomato Papaya</option>
  <option>Durian Tomato Papaya</option>
</select>

Ответ 2

Проблема в том, что Select2 в версии 4.0.0 отделил запрос результатов от отображения результатов. Из-за этого параметр sorter, который вы обычно используете для сортировки результатов, не проходит в запросе, который был сделан (включая термин поиска).

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

var query = {};

$element.select2({
  language: {
    searching: function (params) {
      // Intercept the query as it is happening
      query = params;

      // Change this to be appropriate for your application
      return 'Searching…';
    }
  }
});

Итак, теперь вы можете создать собственный sorter метод, который использует сохраненный query (и используя query.term в качестве условия поиска). Для моего метода сортировки в примере я использую позицию в тексте, в которой результатом поиска является сортировка результатов. Вероятно, это похоже на то, что вы ищете, но это довольно грубая сила, позволяющая обойти это.

function sortBySearchTerm (results) {
  // Don't alter the results being passed in, make a copy
  var sorted = results.slice(0);

  // Array.sort is an in-place sort
  sorted.sort(function (first, second) {
    query.term = query.term || "";

    var firstPosition = first.text.toUpperCase().indexOf(
      query.term.toUpperCase()
    );
    var secondPosition = second.text.toUpperCase().indexOf(
      query.term.toUpperCase()
    );

    return firstPosition - secondPosition;
  });

  return sorted;
};

И это будет сортировать вещи так, как вы хотите это сделать. Вы можете найти полный пример со всеми частями, соединенными вместе ниже. Он использует три примера, которые вы упомянули в своем вопросе.

var query = {};
var $element = $('select');

function sortBySearchTerm (results) {
  // Don't alter the results being passed in, make a copy
  var sorted = results.slice(0);
  
  // Array.sort is an in-place sort
  sorted.sort(function (first, second) {
    query.term = query.term || "";

    var firstPosition = first.text.toUpperCase().indexOf(
      query.term.toUpperCase()
    );
    var secondPosition = second.text.toUpperCase().indexOf(
      query.term.toUpperCase()
    );
    
    return firstPosition - secondPosition;
  });
  
  return sorted;
};

$element.select2({
  sorter: sortBySearchTerm,
  language: {
    searching: function (params) {
      // Intercept the query as it is happening
      query = params;

      // Change this to be appropriate for your application
      return 'Searching…';
    }
  }
});
<link href="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.css" rel="stylesheet"/>

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.js"></script>

<select style="width: 50%">
  <option>banana orange apple</option>
  <option>banana apple orange</option>
  <option>apple banana orange</option>
</select>