Одна из наиболее частых проблем при работе с 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 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());
Awesomplete зависит от корректных CSS-стилей. Частая ошибка —
удаление или переопределение базовых классов .awesomplete и
.awesomplete > ul.
Следствие — список либо не отображается, либо появляется вне контекста страницы.
Типичный конфликт:
ul {
display: none;
}
Это полностью ломает выпадающий список.
Правильный подход — изоляция стилей:
.awesomplete ul {
position: absolute;
z-index: 999;
}
Если 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;
}
При смене страниц или компонентов Awesomplete должен быть корректно
уничтожен. Иначе остаются обработчики keydown,
input, blur.
Типичная ошибка в SPA:
routeChange(() => {
input = document.querySelector("#city");
new Awesomplete(input, { list: cities });
});
Без очистки старого экземпляра создаётся дублирование логики.
При использовании объектов разработчики часто путают отображаемое значение и реальное значение.
Ошибка:
{ label: "Almaty", value: "Almaty" }
При этом ожидается, что value будет кодом или ID, но
вместо этого дублируется label, что делает смысл разделения
бессмысленным.
Корректная модель:
{ label: "Almaty", value: "ALA" }
При частых запросах к API возможна ситуация, когда более старый ответ перезаписывает новый список.
Проблемный сценарий:
Решение — контроль последовательности:
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;
}
});