Загрузка из JSON

Формат данных JSON и требования к структуре

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

Базовый формат элемента:

{
  "value": "1",
  "label": "Элемент 1",
  "selected": false,
  "disabled": false
}

Ключевые поля:

  • value — уникальный идентификатор элемента, используется как фактическое значение при отправке формы
  • label — отображаемый текст
  • selected — флаг предвыбора
  • disabled — блокировка выбора

Дополнительно могут использоваться пользовательские поля, если они не конфликтуют с внутренней логикой Choices.js.


Инициализация пустого компонента перед загрузкой JSON

Перед подгрузкой данных из внешнего источника создаётся пустой экземпляр, который будет динамически наполняться:

const element = document.querySelector('#select');

const choices = new Choices(element, {
  removeItemButton: true,
  searchEnabled: true
});

На этом этапе компонент не содержит данных, либо использует статический набор из HTML.


Загрузка JSON через Fetch API

Основной способ получения данных — использование 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)
  • четвёртый аргумент — очистка текущих данных перед загрузкой

Формат JSON для API-ответа

Типичный ответ сервера:

[
  {
    "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() очищает внутреннее состояние, предотвращая дублирование элементов при повторной загрузке.


Работа с вложенными JSON структурами

При работе с 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 фактически становится источником для реализации серверного поиска.


Кэширование 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

Надёжная интеграция требует обработки ситуаций, когда 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();
  }
}

При ошибке компонент очищается, предотвращая отображение некорректного состояния.


Комбинирование статических и JSON данных

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 в четвёртом аргументе предотвращает очистку уже существующих значений.


Оптимизация больших JSON-наборов

При работе с массивами в десятки тысяч элементов важна минимизация нагрузки на 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);
  }
}

Такой подход снижает вероятность блокировки интерфейса.


Преобразование JSON с нормализацией данных

При интеграции с разными 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);
  });

Нормализация предотвращает ошибки отображения и дублирование.


Синхронизация JSON и состояния формы

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);
    });
  });

Такой подход обеспечивает сохранение пользовательского выбора при обновлении источника данных.