По умолчанию библиотека Awesomplete ориентирована на выбор одного значения из списка подсказок. После выбора элемент полностью заменяет содержимое поля ввода. Для интерфейсов, в которых требуется указывать несколько значений одновременно, стандартное поведение необходимо изменить.
Наиболее распространённые сценарии:
Механизм множественного выбора в Awesomplete строится вокруг двух ключевых элементов:
Стандартный autocomplete работает с единственным значением:
<input id="skills">
new Awesomplete(document.querySelector("#skills"), {
list: ["JavaScript", "Python", "Go", "Rust"]
});
После выбора:
JavaScript
Для множественного выбора поле должно хранить набор значений:
JavaScript, Python, Rust
В этом случае библиотека должна понимать:
Наиболее популярный подход — разделение элементов запятыми.
Пример строки:
JavaScript, Python, Rust
Каждое значение считается отдельным элементом списка.
Awesomplete анализирует всё содержимое input. Для множественного выбора необходимо выделять только последний вводимый фрагмент.
Обычно используется функция split():
function split(input) {
return input.split(/\s*,\s*/);
}
Разбор регулярного выражения:
/\s*,\s*/
Компоненты:
| Конструкция | Значение |
|---|---|
\s* |
любое количество пробелов |
, |
разделитель |
\s* |
пробелы после запятой |
Строка:
JavaScript, Python ,Rust
преобразуется в:
[
"JavaScript",
"Python",
"Rust"
]
После разделения требуется определить текущий вводимый фрагмент.
function extractLast(input) {
return split(input).pop();
}
Метод pop() возвращает последний элемент массива.
Пример:
extractLast("JavaScript, Pyt");
Результат:
"Pyt"
Именно этот фрагмент Awesomplete использует для поиска совпадений.
<input id="languages">
const input = document.querySelector("#languages");
new Awesomplete(input, {
list: [
"JavaScript",
"TypeScript",
"Python",
"Go",
"Rust",
"C++",
"Java"
],
filter: function(text, input) {
return Awesomplete.FILTER_CONTAINS(
text,
extractLast(input)
);
},
item: function(text, input) {
return Awesomplete.ITEM(
text,
extractLast(input)
);
},
replace: function(text) {
const before = split(this.input.value);
before.pop();
before.push(text);
before.push("");
this.input.value = before.join(", ");
}
});
function split(input) {
return input.split(/\s*,\s*/);
}
function extractLast(input) {
return split(input).pop();
}
Метод replace() — центральный механизм множественного
выбора.
Стандартное поведение:
this.input.value = text;
Полностью заменяет содержимое поля.
Для множественного выбора требуется:
const before = split(this.input.value);
Строка:
JavaScript, Pyt
превращается в:
["JavaScript", "Pyt"]
before.pop();
Теперь массив:
["JavaScript"]
before.push(text);
Результат:
["JavaScript", "Python"]
before.push("");
Теперь массив:
["JavaScript", "Python", ""]
Это необходимо для автоматического добавления завершающей запятой.
this.input.value = before.join(", ");
Результат:
JavaScript, Python,
Пользователь сразу может вводить следующий элемент.
Вместо запятых можно использовать любые символы.
function split(input) {
return input.split(/\s*;\s*/);
}
Результат:
JavaScript; Python; Rust
function split(input) {
return input.split(/\s*\|\s*/);
}
Результат:
JavaScript | Python | Rust
function split(input) {
return input.split(/\n+/);
}
Полезно для:
Множественный выбор особенно удобен в textarea.
<textarea id="tags"></textarea>
new Awesomplete("#tags", {
list: [
"frontend",
"backend",
"database",
"devops",
"security"
]
});
В textarea можно:
Без дополнительной логики пользователь может выбирать одинаковые элементы несколько раз.
Пример:
JavaScript, JavaScript
Для предотвращения дубликатов:
replace: function(text) {
let values = split(this.input.value);
values.pop();
if (!values.includes(text)) {
values.push(text);
}
values.push("");
this.input.value = values.join(", ");
}
Иногда требуется считать значения одинаковыми независимо от регистра.
Пример:
javascript
JavaScript
JAVASCRIPT
Проверка:
const exists = values.some(item => {
return item.toLowerCase() === text.toLowerCase();
});
Для ограничения числа выбранных значений:
const LIMIT = 5;
replace: function(text) {
let values = split(this.input.value);
values.pop();
if (values.length >= LIMIT) {
return;
}
values.push(text);
values.push("");
this.input.value = values.join(", ");
}
Множественный выбор может использовать объекты вместо строк.
[
{
label: "JavaScript",
value: 1
},
{
label: "Python",
value: 2
}
]
Пример вставки идентификаторов:
replace: function(item) {
let values = split(this.input.value);
values.pop();
values.push(item.value);
values.push("");
this.input.value = values.join(", ");
}
Результат:
1, 2, 5
Часто требуется:
Схема:
<input id="visible">
<input type="hidden" id="ids">
Видимое поле:
JavaScript, Python
Скрытое поле:
1,2
Пример:
const selectedIds = [];
new Awesomplete(input, {
list: skills,
replace: function(item) {
const labels = split(this.input.value);
labels.pop();
labels.push(item.label);
labels.push("");
this.input.value = labels.join(", ");
if (!selectedIds.includes(item.value)) {
selectedIds.push(item.value);
}
hidden.value = selectedIds.join(",");
}
});
Пользователь может удалять значения через Backspace.
Строка:
JavaScript, Python, Rust
После удаления:
JavaScript, Python
Awesomplete автоматически продолжит работу, если функция
split() корректно обрабатывает строку.
После ввода запятой можно автоматически показывать список:
input.addEventListener("keyup", function(event) {
if (event.key === ",") {
awesomplete.evaluate();
}
});
Это улучшает UX при быстром вводе тегов.
Autocomplete часто комбинируется с клавишей Tab.
input.addEventListener("keydown", function(event) {
if (event.key === "Tab" && awesomplete.opened) {
event.preventDefault();
awesomplete.select();
}
});
Преимущества:
Множественный выбор особенно полезен при динамической загрузке данных.
Пример:
input.addEventListener("input", async function() {
const query = extractLast(input.value);
if (query.length < 2) {
return;
}
const response = await fetch(
"/search?q=" + encodeURIComponent(query)
);
const data = await response.json();
awesomplete.list = data;
});
Для снижения нагрузки:
minChars: 2
Полный пример:
new Awesomplete(input, {
minChars: 2,
list: []
});
Иногда текстовое поле преобразуют в визуальные теги:
[JavaScript] [Python] [Rust]
Схема работы:
Такой подход используется в:
<div id="tags"></div>
<input id="tag-input">
const tags = [];
function renderTags() {
container.innerHTML = "";
tags.forEach(tag => {
const el = document.createElement("span");
el.textContent = tag;
container.appendChild(el);
});
}
После выбора элемента:
replace: function(text) {
if (!tags.includes(text)) {
tags.push(text);
}
renderTags();
this.input.value = "";
}
Множественный выбор обычно отправляется в одном из форматов:
JavaScript,Python,Rust
[
"JavaScript",
"Python",
"Rust"
]
skills[]=JavaScript
skills[]=Python
skills[]=Rust
Если значения сами содержат запятые:
New York, USA
обычное разделение становится некорректным.
Решения:
Если список содержит тысячи элементов:
list: hugeArray
могут появляться:
Оптимизации:
let timer;
input.addEventListener("input", function() {
clearTimeout(timer);
timer = setTimeout(async () => {
const query = extractLast(input.value);
const response = await fetch(
"/api/search?q=" + query
);
awesomplete.list = await response.json();
}, 300);
});
После множественных удалений могут появляться пустые строки:
[
"JavaScript",
"",
"Python"
]
Фильтрация:
values = values.filter(Boolean);
Для удаления лишних пробелов:
values = values.map(item => item.trim());
function split(input) {
return input
.split(",")
.map(item => item.trim())
.filter(Boolean);
}
Это один из наиболее надёжных вариантов обработки множественного ввода.
Awesomplete корректно работает с Unicode-строками:
Москва, Алматы, 東京
Регулярные выражения также поддерживают национальные символы.
В сложных интерфейсах можно:
Awesomplete при этом используется исключительно как autocomplete-движок, а вся логика множественного выбора реализуется поверх библиотеки.