При передаче данных в Slim Select ключевой проблемой становится не сам механизм отрисовки, а качество входного массива. Библиотека ожидает строгую структуру объектов, и любые отклонения приводят к частичной потере опций, некорректному состоянию выбора или визуальным артефактам в списке.
Slim Select работает с массивом объектов вида:
[
{ text: 'Option 1', value: '1' },
{ text: 'Option 2', value: '2' }
]
Критичными являются два поля:
Нарушение этой структуры создаёт каскадные проблемы, особенно при динамической загрузке или преобразовании данных из API.
Типовые нарушения:
valuetextvalue не уникаленnull или undefined в массивеПервый уровень защиты — предварительная очистка массива до инициализации компонента.
function sanitizeOptions(options) {
if (!Array.isArray(options)) return [];
return options
.filter(item => item && typeof item === 'object')
.filter(item => item.text != null && item.value != null)
.map(item => ({
text: String(item.text).trim(),
value: String(item.value)
}));
}
Ключевой момент — приведение типов к строке. Slim Select внутри сравнивает значения строго, и несоответствие типов приводит к невозможности корректного выбора опции.
Особую опасность представляют «тихие» значения:
undefined не вызывает ошибок напрямую, но ломает
рендерnull может попадать в DOM как строкаРасширенная нормализация:
function normalizeValue(value) {
if (value === null || value === undefined) return '';
return String(value);
}
Применение такой нормализации позволяет избежать ситуаций, когда выбранное значение невозможно сопоставить с опцией.
Slim Select не гарантирует уникальность value. При
наличии дублей:
set-операции могут вести себя непредсказуемоУдаление дубликатов:
function uniqueOptions(options) {
const seen = new Set();
return options.filter(item => {
if (seen.has(item.value)) return false;
seen.add(item.value);
return true;
});
}
В сложных интерфейсах важно учитывать, что дубликаты часто появляются не в исходных данных, а после объединения нескольких источников.
API часто возвращают расширенные объекты:
{
id: 1,
name: 'Option',
meta: { ... },
permissions: [...]
}
Прямая передача таких структур приводит к загрязнению состояния и увеличению памяти.
Корректное преобразование:
function mapToSlimSelect(data) {
return data.map(item => ({
text: item.name ?? '',
value: item.id ?? ''
}));
}
Важно избегать передачи meta-данных внутрь Slim Select —
они не используются и увеличивают риск побочных эффектов при
сериализации.
При загрузке данных через API основная проблема — гонки запросов и частичные ответы.
Сценарии:
Защита через проверку актуальности:
let requestId = 0;
async function loadOptions(url) {
const currentRequest = ++requestId;
const response = await fetch(url);
const data = await response.json();
if (currentRequest !== requestId) return [];
return sanitizeOptions(data);
}
Такой подход предотвращает перезапись состояния устаревшими данными.
Пустой массив не является ошибкой, но может ломать UX при отсутствии fallback-состояния.
Рекомендуемая стратегия:
const options = sanitizeOptions(data);
if (options.length === 0) {
slimSelect.setData([{ text: 'Нет данных', value: '', disabled: true }]);
} else {
slimSelect.setData(options);
}
Ключевой момент — явное добавление disabled-элемента вместо пустого состояния.
Slim Select рендерит text в DOM, и некорректные данные
могут привести к вставке HTML.
Проблемные случаи:
<script> в textБазовая защита:
function escapeHtml(str) {
return String(str)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
Применение:
function safeOptions(data) {
return data.map(item => ({
text: escapeHtml(item.text),
value: String(item.value)
}));
}
При использовании setData важно учитывать, что Slim
Select не валидирует вход повторно. Это означает, что некорректные
данные могут быть «закреплены» внутри состояния.
Рекомендуемый подход:
function updateSelect(slimSelect, data) {
const cleaned = uniqueOptions(
sanitizeOptions(data)
);
slimSelect.setData(cleaned);
}
Реальные API часто возвращают смешанные массивы:
[
{ text: 'A', value: '1' },
null,
{ value: '2' },
{ text: 'C' },
'invalid'
]
Жёсткая фильтрация обязательна:
function strictSanitize(options) {
return (options || [])
.filter(item => item && typeof item === 'object')
.filter(item => typeof item.text === 'string' || typeof item.text === 'number')
.filter(item => typeof item.value === 'string' || typeof item.value === 'number')
.map(item => ({
text: String(item.text),
value: String(item.value)
}));
}
При некорректных данных часто возникает проблема: выбранное значение не совпадает ни с одной опцией после обновления массива.
Решение — проверка актуальности выбранного value:
function syncSelected(slimSelect, options) {
const selected = slimSelect.selected();
const exists = options.some(o => o.value === selected);
if (!exists) {
slimSelect.set('');
}
}
Это предотвращает «залипание» несуществующего выбора.
При объединении локальных и серверных данных часто возникает конфликт форматов. Стратегия унификации:
function mergeSources(local, remote) {
return uniqueOptions([
...sanitizeOptions(local),
...sanitizeOptions(remote)
]);
}
Ключевой принцип — нормализация до объединения, а не после.
Для сложных систем важно не только удалять ошибки, но и фиксировать их происхождение:
function debugSanitize(options) {
return (options || []).filter(item => {
const valid = item && item.text && item.value;
if (!valid) {
console.warn('Invalid option:', item);
}
return valid;
});
}
Такой подход позволяет выявлять проблемы на уровне API, а не UI.