Механизм множественного выбора на базе Awesomplete обычно реализуется
через разбиение значения input-поля на токены и хранение выбранных
элементов в отдельной структуре данных. Ограничение количества таких
выборов вводится на уровне логики обработки события выбора, а не внутри
самой библиотеки, поскольку Awesomplete не содержит встроенного
параметра maxItems.
Ключевая идея заключается в синхронизации трёх компонентов:
При каждом выборе элемента проверяется текущее количество уже добавленных значений, и в зависимости от результата либо добавляется новый элемент, либо игнорируется попытка выбора.
Для хранения выбранных элементов используется массив, который синхронизируется с визуальным содержимым input.
const input = document.querySelector("#tags");
const awesomplete = new Awesomplete(input, {
list: ["JavaScript", "TypeScript", "Python", "Go", "Rust", "Java"]
});
const selected = [];
const MAX_SELECTIONS = 3;
Каждое подтверждение выбора через Awesomplete фиксируется событием
awesomplete-selectcomplete.
input.addEventListener("awesomplete-selectcomplete", function (event) {
const value = event.text.value;
});
В этот момент появляется точка контроля: добавление значения либо разрешается, либо блокируется.
Основной механизм ограничения реализуется через проверку длины
массива selected.
input.addEventListener("awesomplete-selectcomplete", function (event) {
const value = event.text.value;
if (selected.length >= MAX_SELECTIONS) {
event.preventDefault?.();
input.value = selected.join(", ");
return;
}
if (!selected.includes(value)) {
selected.push(value);
}
input.value = selected.join(", ");
});
В данной логике ключевым является тот факт, что Awesomplete изменяет значение input автоматически, поэтому требуется принудительная синхронизация отображаемого текста после каждого события выбора.
При множественном выборе значения обычно разделяются запятыми, точками с запятой или другими разделителями. Структура данных синхронизируется через преобразование строки в массив и обратно.
function parseInput(value) {
return value
.split(",")
.map(item => item.trim())
.filter(Boolean);
}
При необходимости пересборки строки используется обратная операция:
function formatOutput(arr) {
return arr.join(", ");
}
Такой подход позволяет централизованно контролировать количество элементов вне зависимости от того, каким образом пользователь вводит данные — через автодополнение или вручную.
Поведение Awesomplete по умолчанию не учитывает ограничения, поэтому список можно скрывать или фильтровать при достижении максимального количества выбранных элементов.
input.addEventListener("awesomplete-open", function () {
if (selected.length >= MAX_SELECTIONS) {
awesomplete.close();
}
});
Альтернативный подход заключается в динамическом изменении источника данных:
function getFilteredList() {
if (selected.length >= MAX_SELECTIONS) {
return [];
}
return ["JavaScript", "TypeScript", "Python", "Go", "Rust", "Java"]
.filter(item => !selected.includes(item));
}
awesomplete.list = getFilteredList();
Обновление списка позволяет исключать уже выбранные элементы и одновременно предотвращать превышение лимита.
Пользователь может вводить значения без использования автодополнения, что требует дополнительной синхронизации при потере фокуса.
input.addEventListener("blur", function () {
const values = parseInput(input.value);
selected.length = 0;
for (let i = 0; i < values.length; i++) {
if (selected.length < MAX_SELECTIONS) {
selected.push(values[i]);
}
}
input.value = formatOutput(selected);
});
В этой модели ручной ввод проходит через тот же ограничитель, что и выбор через список автодополнения, обеспечивая единое поведение системы.
Ограничение количества элементов часто сопровождается необходимостью исключить повторные добавления одного и того же значения.
input.addEventListener("awesomplete-selectcomplete", function (event) {
const value = event.text.value;
if (selected.includes(value)) {
input.value = formatOutput(selected);
return;
}
if (selected.length < MAX_SELECTIONS) {
selected.push(value);
}
input.value = formatOutput(selected);
});
Такой подход предотвращает рост массива за счёт повторных кликов по одному и тому же элементу списка.
При заполнении максимального количества значений логика интерфейса обычно переводится в режим ограничения ввода. Это достигается через изменение состояния поля:
function updateInputState() {
if (selected.length >= MAX_SELECTIONS) {
input.setAttribute("disabled", "true");
} else {
input.removeAttribute("disabled");
}
}
Вызывается после каждого изменения массива:
function sync(value) {
input.value = formatOutput(value);
updateInputState();
}
Удаление элементов из списка требует обратной синхронизации между строкой и массивом.
function removeItem(item) {
const index = selected.indexOf(item);
if (index !== -1) {
selected.splice(index, 1);
}
sync(selected);
}
При наличии UI-элементов (например, тегов) удаление обычно связано с обработчиком клика по конкретному элементу, что позволяет динамически снижать количество выбранных значений и снова открывать возможность добавления новых.
Сложные сценарии используют комбинацию фильтрации списка и ограничения выбора. В этом случае Awesomplete выступает только как слой автодополнения, а логика контроля полностью переносится в пользовательский код.
function canAddMore() {
return selected.length < MAX_SELECTIONS;
}
function getList() {
return ["JavaScript", "TypeScript", "Python", "Go", "Rust", "Java"]
.filter(item => !selected.includes(item));
}
input.addEventListener("input", function () {
awesomplete.list = getList();
});
Такой подход обеспечивает постоянную актуальность списка и исключает возможность выбора недопустимого количества элементов на уровне интерфейса.
Изменение значения input через код требует ручного пересчёта состояния, поскольку Awesomplete не отслеживает внешние изменения как часть внутреннего состояния.
function setValues(values) {
selected.length = 0;
for (const v of values) {
if (selected.length < MAX_SELECTIONS) {
selected.push(v);
}
}
input.value = formatOutput(selected);
updateInputState();
}
Такая функция становится точкой входа для инициализации данных и синхронизации внешних источников с внутренним состоянием компонента.
Основная сложность ограничения количества выборов заключается не в проверке лимита, а в поддержании синхронности между тремя источниками:
Любое рассогласование приводит к некорректному отображению или возможности обхода ограничений. Поэтому все изменения проходят через единый слой синхронизации, в котором выполняются: