Работа с данными в Slim Select строится вокруг модели управления
состоянием компонента через набор методов API и синхронизации с исходным
<select> элементом. Любое изменение набора опций или
выбранных значений должно учитывать внутренний кеш библиотеки,
DOM-состояние и привязку событий.
Основной механизм обновления данных заключается в полном или
частичном пересоздании списка опций. В случаях, когда источник данных
динамический (API, пользовательский ввод, фильтры), применяется метод
setData.
Структура данных для обновления соответствует стандартному формату:
const data = [
{ text: "JavaScript", value: "js" },
{ text: "TypeScript", value: "ts" },
{ text: "Python", value: "py" }
];
Инициализация и последующее обновление:
const select = new SlimSelect({
select: '#languages',
data: [
{ text: 'HTML', value: 'html' },
{ text: 'CSS', value: 'css' }
]
});
// полная замена данных
select.setData(data);
При вызове setData происходит полная переоценка списка:
старые элементы удаляются из внутреннего состояния, пересобирается
DOM-структура, сбрасываются несовместимые выбранные значения.
В сценариях, где требуется сохранить существующие данные и добавить новые, используется комбинированный подход: извлечение текущего состояния и расширение массива.
const currentData = select.data.data;
const newItems = [
{ text: "Go", value: "go" },
{ text: "Rust", value: "rust" }
];
select.setData([...currentData, ...newItems]);
Такой подход сохраняет непрерывность состояния и предотвращает сброс выбранных значений, если новые элементы не конфликтуют с уже выбранными значениями.
Внутренняя архитектура Slim Select не предоставляет прямого метода для точечного обновления одной опции без пересборки списка. Однако имитация подобного поведения возможна через:
setData.Пример изменения одного элемента:
const upd ated = select.data.data.map(item => {
if (item.value === 'js') {
return { ...item, text: 'JavaScript ES' };
}
return item;
});
select.setData(updated);
При таком подходе обновляется только логическая модель, но визуально список полностью перерисовывается.
Часто данные поступают асинхронно. В таких случаях важно учитывать момент инициализации и готовность компонента к обновлению.
async function loadLanguages() {
const response = await fetch('/api/languages');
const result = await response.json();
select.setData(result.map(item => ({
text: item.name,
value: item.code
})));
}
При асинхронной загрузке важно учитывать, что повторный вызов
setData может сбрасывать пользовательский выбор, если он
был сделан до обновления.
При динамическом обновлении часто требуется сохранить текущий выбор. Для этого применяется стратегия сохранения массива значений до обновления и последующее восстановление.
const selectedValues = select.selected();
const updatedData = [
{ text: 'HTML', value: 'html' },
{ text: 'CSS', value: 'css' },
{ text: 'JavaScript', value: 'js' }
];
select.setData(updatedData);
select.setSelected(selectedValues);
Такой подход особенно важен при фильтрации или обновлении справочников, где пользовательский выбор не должен сбрасываться.
При обновлении данных с группировкой необходимо учитывать вложенную структуру:
const groupedData = [
{
label: 'Frontend',
options: [
{ text: 'React', value: 'react' },
{ text: 'Vue', value: 'vue' }
]
},
{
label: 'Backend',
options: [
{ text: 'Node.js', value: 'node' },
{ text: 'Django', value: 'django' }
]
}
];
select.setData(groupedData);
При обновлении таких структур важно соблюдать корректность вложенности, поскольку библиотека ожидает строгий формат группировки. Любое отклонение приводит к потере отображения или некорректной сборке списка.
В некоторых сценариях требуется гарантированно сбросить текущее состояние перед загрузкой нового набора. Это достигается комбинацией очистки выбора и установки пустого массива.
select.setSelected([]);
select.setData([]);
После этого можно безопасно загружать новые данные без риска конфликта состояний.
Обновление данных часто привязывается к пользовательским событиям интерфейса:
document.querySelector('#filter').addEventListener('input', async (e) => {
const query = e.target.value;
const response = await fetch(`/api/search?q=${query}`);
const result = await response.json();
select.setData(result);
});
Такой механизм превращает компонент в реактивный элемент интерфейса, где список опций напрямую зависит от внешнего состояния.
В случаях, когда состояние становится несогласованным, применяется полное уничтожение и повторная инициализация:
select.destroy();
const newSelect = new SlimSelect({
select: '#languages',
data: freshData
});
Этот подход используется при смене контекста страницы, модульной подгрузке или полной замене источника данных.
При работе с локальной фильтрацией часто требуется временно менять набор отображаемых опций, не затрагивая исходный источник данных:
const original = select.data.data;
function filterByLetter(letter) {
const filtered = original.filter(item =>
item.text.startsWith(letter)
);
select.setData(filtered);
}
Таким образом формируется слой представления, отделённый от исходной модели данных.
При работе с тысячами элементов важным фактором становится
производительность. Полная перерисовка через setData может
приводить к заметным задержкам. В таких случаях используется
предварительная подготовка данных:
const optimized = rawData
.filter(Boolean)
.map(item => ({
text: item.title.trim(),
value: item.id
}));
select.setData(optimized);
Снижение объёма операций до передачи в компонент уменьшает нагрузку на DOM и ускоряет рендеринг.
При динамическом обновлении необходимо учитывать возможные несоответствия между выбранными значениями и новым набором опций. Если выбранное значение отсутствует в обновлённом списке, оно автоматически становится невалидным и удаляется из состояния выбора.
Это поведение требует явной проверки перед обновлением:
const validValues = new Se t(newData.map(i => i.value));
const filteredSelected = select.selected().filter(v =>
validValues.has(v)
);
select.setData(newData);
select.setSelected(filteredSelected);
Такой контроль предотвращает потерю логики пользовательского интерфейса.
При сложных интерфейсах, где данные зависят от нескольких источников, применяется последовательное обновление:
async function refresh() {
const [categories, items] = await Promise.all([
fetch('/api/categories').then(r => r.json()),
fetch('/api/items').then(r => r.json())
]);
const merged = categories.map(cat => ({
label: cat.name,
options: items
.filter(i => i.categoryId === cat.id)
.map(i => ({ text: i.name, value: i.id }))
}));
select.setData(merged);
}
Такая структура позволяет строить зависимые списки без нарушения внутренней логики компонента.
При интенсивных изменениях данных важно учитывать, что каждое
setData инициирует перерасчёт DOM. При частых вызовах может
возникнуть эффект «дребезга» интерфейса. Для его снижения применяется
агрегация обновлений:
let timeout;
function update(data) {
clearTimeout(timeout);
timeout = setTimeout(() => {
select.setData(data);
}, 100);
}
Этот подход стабилизирует поведение интерфейса при потоковой передаче данных.
Внутреннее состояние Slim Select включает не только список опций, но и активные фильтры, выбранные значения и кеш отображения. Поэтому любое обновление данных рассматривается как операция высокой значимости, затрагивающая весь жизненный цикл компонента.
Корректная работа с обновлением требует согласованности между внешним источником данных и текущим состоянием интерфейса, иначе возникают рассинхронизации, выражающиеся в некорректном отображении или потере выбора.