Работа с состоянием формы в интерфейсах, использующих кастомные
элементы выбора, требует учета того, что стандартное поведение
<select> часто заменяется программной логикой. В
библиотеке Choices.js управление состоянием строится вокруг
синхронизации внутреннего представления выбранных значений и внешнего
хранилища данных.
Внутреннее состояние компонента строится на основе массива выбранных значений, где каждый элемент может содержать:
value)label)Экземпляр Choices предоставляет методы для получения текущего состояния:
getValue() — возвращает выбранные элементы в виде
объектовgetValue(true) — возвращает только значения без
метаданныхsetValue() — программная установка состоянияclearStore() — очистка текущих данныхСохранение состояния формы базируется на сериализации результата
getValue() и последующем восстановлении через
setValue().
При необходимости сохранения состояния между перезагрузками страницы используется преобразование текущего выбора в строковый формат.
Наиболее распространённые подходы:
const selected = choices.getValue(true);
localStorage.setItem('form_state', JSON.stringify(selected));
Данный вариант применяется, когда источником данных является статический список опций.
const selected = choices.getValue();
sessionStorage.setItem('form_state', JSON.stringify(selected));
Такой подход необходим при динамических списках, где важны дополнительные свойства (например, категории, идентификаторы, флаги активности).
После инициализации экземпляра происходит обратная операция десериализации и передачи данных в компонент.
const saved = JSON.parse(localStorage.getItem('form_state') || '[]');
choices.setValue(saved);
При восстановлении важно учитывать структуру данных:
Оптимальная стратегия — привязка сохранения к событию изменения выбора:
element.addEventListener('change', () => {
const state = choices.getValue();
localStorage.setItem('form_state', JSON.stringify(state));
});
Choices.js генерирует собственные события изменения, которые можно использовать для более точной синхронизации:
element.addEventListener('addItem', () => {
persist();
});
element.addEventListener('removeItem', () => {
persist();
});
Выбор механизма хранения определяется жизненным циклом данных:
Используется при необходимости сохранения состояния только в рамках одной сессии браузера. После закрытия вкладки данные удаляются.
Применяется для долгосрочного сохранения состояния формы между визитами пользователя.
При использовании динамических источников данных порядок инициализации становится критичным. Частая проблема — попытка восстановить состояние до загрузки списка опций.
Корректная последовательность:
fetch('/api/options')
.then(r => r.json())
.then(data => {
const choices = new Choices(select, {
choices: data
});
const saved = JSON.parse(localStorage.getItem('state') || '[]');
choices.setValue(saved);
});
Состояние может стать неконсистентным, если:
value у опцийДля обработки таких случаев используется фильтрация:
const validValues = saved.filter(item =>
choices._store.choices.some(c => c.value === item.value)
);
Для multi-select сценариев состояние хранится как массив:
const values = choices.getValue(true);
localStorage.setItem('multi', JSON.stringify(values));
При восстановлении:
choices.setValue(JSON.parse(localStorage.getItem('multi')));
Особенность заключается в том, что порядок элементов может быть важен, если UI поддерживает сортировку выбранных значений.
При отправке формы состояние часто синхронизируется с скрытыми полями:
form.addEventListener('submit', () => {
hiddenInput.value = JSON.stringify(choices.getValue(true));
});
Такой подход обеспечивает совместимость с классической серверной обработкой форм.
Сброс формы должен сопровождаться удалением сохраненного состояния:
choices.clearStore();
localStorage.removeItem('form_state');
Дополнительно может потребоваться сброс DOM-значений:
form.reset();
В одностраничных приложениях состояние часто синхронизируется с роутером или глобальным стором.
Подходы:
Пример промежуточного слоя:
function syncState() {
store.dispatch('updateChoices', choices.getValue(true));
}
При частых изменениях (поиск, ввод, удаление) возникает избыточное количество операций записи в storage. Используется debounce:
const persist = debounce(() => {
localStorage.setItem('state', JSON.stringify(choices.getValue()));
}, 300);
Это снижает нагрузку на браузер и предотвращает блокировки UI.
Choices позволяет расширять элементы через кастомные свойства. При сохранении состояния такие данные могут быть критичны:
{
value: '1',
label: 'Option',
customProperties: {
group: 'A',
priority: 10
}
}
Сериализация должна учитывать эти поля, иначе восстановление приведет к потере логики отображения.
Некоторые элементы могут быть временно недоступны. При сохранении состояния важно учитывать:
При восстановлении:
if (option.disabled) continue;
choices.setChoiceByValue(option.value);
Для сложных форм применяется контроль версий состояния:
const state = {
version: 1,
values: choices.getValue(true)
};
При изменении структуры формы версия позволяет выполнять миграцию данных.
В формах с несколькими селектами состояние может зависеть друг от друга. Тогда используется единое хранилище:
const globalState = {
country: [],
city: []
};
И синхронизация через общий обработчик событий:
function updateState(name, values) {
globalState[name] = values;
}
При повторной инициализации компонента важно избегать наложения старого состояния:
choices.destroy();
choices = new Choices(select, options);
Choices поддерживает поиск внутри списка. При необходимости можно сохранять:
sessionStorage.setItem('search', input.value);
Система сохранения состояния в Choices.js обычно включает: