Типичные ошибки

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

const input = document.getElementById("city");
const awesomplete = new Awesomplete(input, {
  list: ["Almaty", "Astana", "Karaganda"]
});

Если input равен null, библиотека не выбросит понятную ошибку сразу, но автодополнение просто не заработает. Часто это происходит при подключении скрипта в <head> без DOMContentLoaded.

Корректный подход:

document.addEventListener("DOMContentLoaded", () => {
  const input = document.querySelector("#city");
  new Awesomplete(input, {
    list: ["Almaty", "Astana", "Karaganda"]
  });
});

Использование неподдерживаемых форматов данных

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

Некорректный вариант:

list: [
  { name: "Almaty" },
  { name: "Astana" }
]

В этом случае библиотека не сможет корректно отобразить подсказки, так как ожидает строго определённые ключи.

Правильный вариант:

list: [
  { label: "Almaty", value: "ALA" },
  { label: "Astana", value: "TSE" }
]

Либо простой формат:

list: ["Almaty", "Astana"]

Ошибки при динамической загрузке данных

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

Типичная ошибка:

fetch("/cities")
  .then(res => res.json())
  .then(data => {
    awesomplete.list = data;
  });

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

Более надёжный подход — принудительное обновление через повторное присваивание или пересоздание экземпляра:

awesomplete.list = data;
awesomplete.evaluate();

В сложных случаях используется пересоздание:

awesomplete.destroy();
awesomplete = new Awesomplete(input, { list: data });

Повторная инициализация на одном элементе

Распространённая ошибка — создание нескольких экземпляров Awesomplete для одного input. Это приводит к дублированию обработчиков событий и неконтролируемому поведению интерфейса.

new Awesomplete(input, { list: cities });
new Awesomplete(input, { list: countries });

В результате события input, blur, keydown начинают конфликтовать.

Правильный подход — хранить ссылку на экземпляр:

if (input.awesomplete) {
  input.awesomplete.list = newList;
} else {
  input.awesomplete = new Awesomplete(input, { list: newList });
}

Игнорирование жизненного цикла DOM-элементов

При удалении элементов из DOM Awesomplete не всегда автоматически освобождает обработчики событий. Это приводит к утечкам памяти, особенно в SPA-приложениях.

Проблемный сценарий:

container.innerHTML = "";

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

Решение — явное уничтожение:

awesomplete.destroy();
input.remove();

Ошибки обработки событий выбора

Событие выбора элемента (awesomplete-selectcomplete) часто используется неправильно. Разработчики пытаются читать значение напрямую из input до завершения внутреннего обновления.

Некорректный подход:

input.addEventListener("awesomplete-selectcomplete", () => {
  console.log(input.value);
});

В некоторых случаях значение ещё не синхронизировано с выбранным объектом.

Корректнее использовать объект события:

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

Неправильная фильтрация данных

Awesomplete по умолчанию использует простую фильтрацию по подстроке. Ошибка возникает, когда разработчики пытаются внедрить сложную логику, но не переопределяют filter.

Пример некорректной попытки:

list: cities.filter(c => c.startsWith(query))

Здесь query недоступен в момент инициализации списка.

Правильный способ — использование кастомного фильтра:

Awesomplete.prototype.filter = function (text, input) {
  return text.toLowerCase().includes(input.toLowerCase());
};

Проблемы с производительностью на больших списках

При передаче массива из десятков тысяч элементов Awesomplete начинает тормозить из-за линейного перебора.

Ошибочная практика:

list: hugeArray

Даже при коротком вводе происходит полный проход по массиву.

Решения:

  • предварительная индексация данных
  • сокращение списка перед передачей
  • использование серверной фильтрации

Пример серверного подхода:

input.addEventListener("input", async (e) => {
  const res = await fetch(`/search?q=${e.target.value}`);
  awesomplete.list = await res.json();
});

Ошибки чувствительности к регистру

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

Проблемный вариант:

return text.includes(input);

Исправление:

return text.toLowerCase().includes(input.toLowerCase());

Конфликты с CSS и отображением списка

Awesomplete зависит от корректных CSS-стилей. Частая ошибка — удаление или переопределение базовых классов .awesomplete и .awesomplete > ul.

Следствие — список либо не отображается, либо появляется вне контекста страницы.

Типичный конфликт:

ul {
  display: none;
}

Это полностью ломает выпадающий список.

Правильный подход — изоляция стилей:

.awesomplete ul {
  position: absolute;
  z-index: 999;
}

Проблемы с позиционированием при изменении layout

Если input находится внутри контейнеров с overflow: hidden, список подсказок может обрезаться.

Ошибка архитектуры:

.container {
  overflow: hidden;
}

Awesomplete создаёт выпадающий список, который выходит за пределы контейнера, но оказывается скрытым.

Решение — изменение контекста позиционирования или перенос списка в body через кастомную реализацию.


Неверное использование пользовательских шаблонов

При кастомизации отображения (item, replace) часто ломается логика выбора значения.

Проблема:

item: (text) => `<li>${text}</li>`

Здесь нарушается ожидаемая структура DOM-элемента, и событие выбора перестаёт корректно работать.

Корректный вариант:

item: (text, input) => {
  const li = document.createElement("li");
  li.textContent = text;
  return li;
}

Игнорирование destroy и очистки состояния

При смене страниц или компонентов Awesomplete должен быть корректно уничтожен. Иначе остаются обработчики keydown, input, blur.

Типичная ошибка в SPA:

routeChange(() => {
  input = document.querySelector("#city");
  new Awesomplete(input, { list: cities });
});

Без очистки старого экземпляра создаётся дублирование логики.


Неправильная работа с value и label

При использовании объектов разработчики часто путают отображаемое значение и реальное значение.

Ошибка:

{ label: "Almaty", value: "Almaty" }

При этом ожидается, что value будет кодом или ID, но вместо этого дублируется label, что делает смысл разделения бессмысленным.

Корректная модель:

{ label: "Almaty", value: "ALA" }

Игнорирование асинхронных гонок

При частых запросах к API возможна ситуация, когда более старый ответ перезаписывает новый список.

Проблемный сценарий:

  • ввод: “a” → запрос 1
  • ввод: “al” → запрос 2
  • ответ 1 приходит позже и перезаписывает результат

Решение — контроль последовательности:

let lastRequestId = 0;

input.addEventListener("input", async (e) => {
  const id = ++lastRequestId;
  const res = await fetch(`/search?q=${e.target.value}`);
  const data = await res.json();

  if (id === lastRequestId) {
    awesomplete.list = data;
  }
});