Choices.js работает с унифицированной моделью данных, в которой каждый элемент списка представляет собой объект с фиксированными полями. При загрузке из JSON критически важно соблюдать структуру, которую ожидает библиотека, иначе элементы не будут отображены или корректно обработаны.
Базовый формат элемента:
{
"value": "1",
"label": "Элемент 1",
"selected": false,
"disabled": false
}
Ключевые поля:
Дополнительно могут использоваться пользовательские поля, если они не конфликтуют с внутренней логикой Choices.js.
Перед подгрузкой данных из внешнего источника создаётся пустой экземпляр, который будет динамически наполняться:
const element = document.querySelector('#select');
const choices = new Choices(element, {
removeItemButton: true,
searchEnabled: true
});
На этом этапе компонент не содержит данных, либо использует статический набор из HTML.
Основной способ получения данных — использование fetch с
последующей передачей результата в Choices.js.
fetch('/api/items.json')
.then(response => response.json())
.then(data => {
choices.setChoices(data, 'value', 'label', true);
})
.catch(error => {
console.error('Ошибка загрузки JSON:', error);
});
Параметры setChoices:
value)label)Типичный ответ сервера:
[
{
"value": "ru",
"label": "Русский"
},
{
"value": "en",
"label": "English"
},
{
"value": "de",
"label": "Deutsch"
}
]
Choices.js не требует дополнительной обёртки, если используется
setChoices напрямую.
При необходимости загрузки данных до отображения интерфейса применяется асинхронный подход:
async function loadChoices() {
const response = await fetch('/api/options.json');
const data = await response.json();
choices.setChoices(data, 'value', 'label', true);
}
loadChoices();
Такой подход позволяет гарантировать, что компонент получит данные до взаимодействия пользователя с интерфейсом.
Choices.js поддерживает повторное заполнение списка без пересоздания экземпляра.
function refreshData(newData) {
choices.clearStore();
choices.setChoices(newData, 'value', 'label', true);
}
Метод clearStore() очищает внутреннее состояние,
предотвращая дублирование элементов при повторной загрузке.
При работе с API, возвращающими вложенные объекты, требуется предварительное преобразование данных.
Исходный JSON:
{
"items": [
{ "id": 1, "title": "Москва" },
{ "id": 2, "title": "Казань" }
]
}
Преобразование:
fetch('/api/cities')
.then(res => res.json())
.then(data => {
const formatted = data.items.map(item => ({
value: item.id,
label: item.title
}));
choices.setChoices(formatted, 'value', 'label', true);
});
Choices.js поддерживает сценарий, при котором данные подгружаются по мере ввода текста. Это особенно полезно при работе с большими JSON-источниками.
const searchInput = document.querySelector('#select');
const choices = new Choices(searchInput, {
searchEnabled: true,
shouldSort: false
});
searchInput.addEventListener('search', async (event) => {
const query = event.detail.value;
const response = await fetch(`/api/search?q=${query}`);
const data = await response.json();
choices.setChoices(data, 'value', 'label', true);
});
При таком подходе JSON фактически становится источником для реализации серверного поиска.
Для уменьшения количества запросов применяется локальное кэширование:
let cache = null;
async function getData() {
if (cache) return cache;
const response = await fetch('/api/options.json');
cache = await response.json();
return cache;
}
getData().then(data => {
choices.setChoices(data, 'value', 'label', true);
});
Такой механизм снижает нагрузку на сервер и ускоряет повторную инициализацию компонента.
Надёжная интеграция требует обработки ситуаций, когда JSON недоступен или повреждён:
async function safeLoad() {
try {
const response = await fetch('/api/options.json');
if (!response.ok) {
throw new Error('Сервер вернул ошибку');
}
const data = await response.json();
choices.setChoices(data, 'value', 'label', true);
} catch (error) {
console.error('Ошибка загрузки данных:', error);
choices.clearStore();
}
}
При ошибке компонент очищается, предотвращая отображение некорректного состояния.
Choices.js позволяет объединять предзагруженные значения и данные из JSON:
choices.setChoices([
{ value: 'default', label: 'По умолчанию' }
], 'value', 'label', false);
fetch('/api/options.json')
.then(res => res.json())
.then(data => {
choices.setChoices(data, 'value', 'label', false);
});
Параметр false в четвёртом аргументе предотвращает
очистку уже существующих значений.
При работе с массивами в десятки тысяч элементов важна минимизация нагрузки на DOM. В таких случаях применяется частичная загрузка:
function chunkArray(arr, size) {
const result = [];
for (let i = 0; i < arr.length; i += size) {
result.push(arr.slice(i, i + size));
}
return result;
}
async function loadInChunks(data) {
const chunks = chunkArray(data, 500);
for (const chunk of chunks) {
choices.setChoices(chunk, 'value', 'label', false);
}
}
Такой подход снижает вероятность блокировки интерфейса.
При интеграции с разными API часто требуется приведение типов и очистка данных:
function normalize(items) {
return items
.filter(item => item && item.id && item.name)
.map(item => ({
value: String(item.id),
label: item.name.trim()
}));
}
fetch('/api/raw')
.then(res => res.json())
.then(data => {
choices.setChoices(normalize(data), 'value', 'label', true);
});
Нормализация предотвращает ошибки отображения и дублирование.
Choices.js сохраняет внутреннее состояние выбранных элементов, поэтому при обновлении JSON важно учитывать текущий выбор:
const selected = choices.getValue(true);
fetch('/api/options.json')
.then(res => res.json())
.then(data => {
choices.setChoices(data, 'value', 'label', true);
selected.forEach(val => {
choices.setChoiceByValue(val);
});
});
Такой подход обеспечивает сохранение пользовательского выбора при обновлении источника данных.