Миграция с других библиотек

Переход на Awesomplete в существующих проектах почти всегда связан с заменой более тяжёлых или фреймворк-зависимых решений автодополнения. Основная особенность миграции заключается в том, что Awesomplete минималистична: отсутствует жёсткая привязка к DOM-структурам, нет обязательных зависимостей и почти вся логика строится вокруг одного конструктора и набора атрибутов элемента <input>.

Ключевая задача миграции — не переписать поведение один в один, а адаптировать существующие сценарии к более низкоуровневой модели управления списком подсказок.


Миграция с jQuery UI Autocomplete

jQuery UI Autocomplete предполагает декларативное поведение через вызов метода .autocomplete() и богатую систему событий. В Awesomplete аналогичная логика распределяется между инициализацией и событиями экземпляра.

Было (jQuery UI):

$("#city").autocomplete({
  source: ["Berlin", "Bern", "Barcelona"],
  minLength: 2,
  select: function(event, ui) {
    console.log(ui.item.value);
  }
});

Стало (Awesomplete):

const input = document.querySelector("#city");

const awesomplete = new Awesomplete(input, {
  minChars: 2,
  list: ["Berlin", "Bern", "Barcelona"]
});

input.addEventListener("awesomplete-selectcomplete", function(e) {
  console.log(e.text.value);
});

Ключевые изменения:

  • source заменяется на list
  • minLength становится minChars
  • select превращается в DOM-событие awesomplete-selectcomplete
  • управление осуществляется через объект Awesomplete, а не через jQuery-обёртку

Миграция с Typeahead.js

Typeahead.js использует сложную модель datasets и Bloodhound для поиска. Awesomplete заменяет это простой функцией или массивом.

Было (Typeahead.js):

var engine = new Bloodhound({
  datumTokenizer: Bloodhound.tokenizers.whitespace,
  queryTokenizer: Bloodhound.tokenizers.whitespace,
  local: ["Amsterdam", "Athens", "Auckland"]
});

$("#city").typeahead(null, {
  source: engine
});

Стало (Awesomplete):

const input = document.querySelector("#city");

new Awesomplete(input, {
  list: ["Amsterdam", "Athens", "Auckland"]
});

Отличия архитектуры:

  • Bloodhound полностью исключается
  • отсутствует токенизация на уровне библиотеки
  • фильтрация выполняется встроенным механизмом Awesomplete
  • нет разделения на datasets

Миграция с Select2

Select2 совмещает автодополнение и кастомные <select> компоненты. Awesomplete работает исключительно с <input>, поэтому требуется изменение модели данных.

Было (Select2):

$("#city").select2({
  data: [
    { id: 1, text: "Berlin" },
    { id: 2, text: "Bern" }
  ]
});

Стало (Awesomplete):

const input = document.querySelector("#city");

new Awesomplete(input, {
  list: ["Berlin", "Bern"]
});

Важные преобразования:

  • объект {id, text} заменяется на строку
  • если требуется сохранение id, используется кастомный формат:
new Awesomplete(input, {
  list: [
    "1|Berlin",
    "2|Bern"
  ]
});

И последующая обработка:

input.addEventListener("awesomplete-selectcomplete", function(e) {
  const [id, text] = e.text.value.split("|");
});

Миграция с jQuery Autocomplete (плагин DevBridge)

Этот плагин часто используется в старых проектах и имеет AJAX-ориентированную модель.

Было:

$("#city").autocomplete({
  serviceUrl: "/api/cities",
  onSelect: function(suggestion) {
    console.log(suggestion.value);
  }
});

Стало:

const input = document.querySelector("#city");

const awesomplete = new Awesomplete(input, {
  minChars: 1
});

input.addEventListener("input", async function() {
  const res = await fetch(`/api/cities?q=${this.value}`);
  const data = await res.json();

  awesomplete.list = data.map(item => item.name);
  awesomplete.evaluate();
});

Архитектурные изменения:

  • запросы полностью выносятся наружу
  • Awesomplete не управляет сетью
  • обновление списка происходит через list + evaluate()
  • контроль дебаунса реализуется вручную

Миграция с Choices.js

Choices.js работает с <select multiple> и тегами. Awesomplete не поддерживает мультиселект напрямую, поэтому требуется адаптация логики.

Было:

new Choices("#city", {
  choices: [
    { value: "Berlin", label: "Berlin" },
    { value: "Bern", label: "Bern" }
  ],
  removeItemButton: true
});

Стало (через внешний слой управления):

const input = document.querySelector("#city");
const selected = [];

const awesomplete = new Awesomplete(input, {
  list: ["Berlin", "Bern"]
});

input.addEventListener("awesomplete-selectcomplete", function(e) {
  selected.push(e.text.value);
  input.value = "";
});

Отличия:

  • отсутствует встроенная модель тегов
  • управление выбранными элементами переносится в приложение
  • UI мультиселекта строится вручную

Перенос кастомной логики фильтрации

Во многих библиотеках фильтрация происходит на уровне источника данных. Awesomplete использует встроенный фильтр, но допускает переопределение.

Было (кастомный matcher):

matcher: function(item, query) {
  return item.startsWith(query);
}

Стало:

new Awesomplete(input, {
  list: ["Berlin", "Bern", "Barcelona"],
  filter: function(text, input) {
    return text.toLowerCase().indexOf(input.toLowerCase()) === 0;
  }
});

Перенос асинхронных источников данных

Миграция часто требует замены встроенных AJAX-механизмов на ручное управление списком.

Общая схема перехода:

  1. Перехват события input
  2. Выполнение запроса
  3. Обновление awesomplete.list
  4. Принудительная переоценка через evaluate()
const input = document.querySelector("#city");

const awesomplete = new Awesomplete(input, {
  minChars: 2,
  list: []
});

let timeout;

input.addEventListener("input", function() {
  clearTimeout(timeout);

  timeout = setTimeout(async () => {
    const res = await fetch(`/api/search?q=${this.value}`);
    const data = await res.json();

    awesomplete.list = data;
    awesomplete.evaluate();
  }, 200);
});

Типичные ошибки при миграции

Потеря контроля над DOM-событиями

В старых библиотеках часто используются собственные события. В Awesomplete необходимо использовать стандартные DOM event listeners.

Попытка сохранить jQuery-цепочки

Awesomplete не возвращает jQuery-объект, поэтому конструкции вида:

$("#city").data().autocomplete

становятся неприменимыми.

Игнорирование evaluate()

При динамическом обновлении списка забывают вызвать перерасчёт, из-за чего UI не обновляется.


Адаптация архитектуры данных

В процессе миграции часто происходит переход от сложных структур:

{ id: 10, name: "Berlin", country: "DE" }

к упрощённым строкам или плоским форматам:

"Berlin"

При необходимости сохранения метаданных используется сериализация:

"10::Berlin::DE"

с последующим разбором при выборе.


Перенос кастомного UI рендеринга

Некоторые библиотеки позволяют переопределять шаблоны. Awesomplete делает ставку на минимальный UI, поэтому кастомизация достигается через CSS и частично через item форматирование.

new Awesomplete(input, {
  list: ["Berlin", "Bern"]
});

Стилизация:

.awesomplete ul {
  border: 1px solid #ccc;
}

.awesomplete li[aria-selected="true"] {
  background: #eee;
}

Итоговая трансформация подхода

Переход на Awesomplete почти всегда означает упрощение архитектуры автодополнения. Вместо сложных систем с несколькими уровнями абстракции остаётся один объект, один input и явное управление данными.