Работа с удалёнными источниками данных в Slim Select строится вокруг динамического наполнения списка опций после инициализации компонента или в момент взаимодействия пользователя с полем. Основная задача такого подхода — минимизировать первоначальный объём данных, ускорить загрузку интерфейса и обеспечить актуальность информации, поступающей с backend-сервера.
Slim Select не навязывает строгий механизм загрузки данных с сервера.
Вместо этого используется стандартный подход: получение данных через
fetch, XMLHttpRequest или любые сторонние
HTTP-клиенты с последующей передачей результата в экземпляр селекта.
Структура данных, возвращаемых сервером, как правило, должна быть нормализована:
[
{ "text": "Москва", "value": "moscow" },
{ "text": "Санкт-Петербург", "value": "spb" },
{ "text": "Казань", "value": "kazan" }
]
После получения данных выполняется их преобразование в формат, понятный Slim Select.
Часто компонент создаётся без предзагруженных опций, чтобы избежать лишних запросов и ускорить рендер:
<select id="citySelect"></select>
const slimSelect = new SlimSelect({
select: '#citySelect',
placeholder: 'Выберите значение'
});
На этом этапе список пуст, а данные загружаются отдельно.
Один из наиболее распространённых сценариев — загрузка списка сразу после инициализации:
fetch('/api/cities')
.then(response => response.json())
.then(data => {
slimSelect.setData(
data.map(item => ({
text: item.text,
value: item.value
}))
);
});
Метод setData полностью заменяет текущий список опций,
что делает его удобным для первичной инициализации.
В реальных интерфейсах данные часто зависят от других параметров формы. Например, список городов может зависеть от выбранной страны.
const countrySelect = new SlimSelect({
select: '#countrySelect',
onChange: (info) => {
loadCities(info.value);
}
});
function loadCities(countryId) {
fetch(`/api/cities?country=${countryId}`)
.then(res => res.json())
.then(data => {
slimSelect.setData(
data.map(city => ({
text: city.name,
value: city.id
}))
);
});
}
Здесь ключевую роль играет реактивное обновление списка через событие
onChange.
Для больших наборов данных используется стратегия загрузки по мере ввода текста. Такой подход снижает нагрузку на сервер и клиент.
let searchTimeout;
const slimSelect = new SlimSelect({
select: '#searchSelect',
searchPlaceholder: 'Введите запрос...',
onSearch: (query) => {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
fetch(`/api/search?q=${encodeURIComponent(query)}`)
.then(res => res.json())
.then(data => {
slimSelect.setData(
data.map(item => ({
text: item.label,
value: item.id
}))
);
});
}, 300);
}
});
Задержка (debounce) предотвращает избыточные запросы при
быстром наборе текста.
При повторяющихся запросах целесообразно использовать кэширование результатов, чтобы снизить количество обращений к серверу.
const cache = {};
function getCities(query) {
if (cache[query]) {
return Promise.resolve(cache[query]);
}
return fetch(`/api/cities?q=${query}`)
.then(res => res.json())
.then(data => {
cache[query] = data;
return data;
});
}
Далее кэш интегрируется в обработчик поиска:
onSearch: (query) => {
getCities(query).then(data => {
slimSelect.setData(
data.map(i => ({
text: i.name,
value: i.id
}))
);
});
}
В некоторых сценариях требуется не полная замена данных, а добавление новых элементов. Для этого используется комбинирование текущего состояния с новыми значениями.
function appendOptions(newItems) {
const currentData = slimSelect.getData();
const merged = [
...currentData,
...newItems.map(i => ({
text: i.text,
value: i.value
}))
];
slimSelect.setData(merged);
}
Такой подход полезен при пагинации или бесконечной прокрутке.
При больших объёмах данных сервер может отдавать результаты частями:
let page = 1;
let loading = false;
function loadMore() {
if (loading) return;
loading = true;
fetch(`/api/items?page=${page}`)
.then(res => res.json())
.then(data => {
const formatted = data.items.map(i => ({
text: i.name,
value: i.id
}));
slimSelect.setData([
...slimSelect.getData(),
...formatted
]);
page++;
loading = false;
});
}
Пагинация особенно эффективна при работе с каталогами и справочниками.
Сетевые запросы всегда требуют обработки ошибок, особенно при динамическом наполнении селекта.
fetch('/api/options')
.then(res => {
if (!res.ok) {
throw new Error('Ошибка загрузки');
}
return res.json();
})
.then(data => {
slimSelect.setData(data);
})
.catch(() => {
slimSelect.setData([]);
});
При ошибке список очищается или заменяется fallback-значениями.
В некоторых случаях выбранное значение должно немедленно отправляться на backend:
const slimSelect = new SlimSelect({
select: '#statusSelect',
onChange: (info) => {
fetch('/api/save-status', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
status: info.value
})
});
}
});
Такой подход используется в интерфейсах администрирования и CRM-системах.
Запросы к серверу часто зависят от нескольких факторов формы:
function buildQuery() {
const region = document.querySelector('#region').value;
const type = document.querySelector('#type').value;
return `/api/items?region=${region}&type=${type}`;
}
function reloadData() {
fetch(buildQuery())
.then(res => res.json())
.then(data => {
slimSelect.setData(data);
});
}
Такой подход позволяет строить сложные фильтрационные системы без перегрузки интерфейса.
Для снижения нагрузки применяется комбинирование debounce и минимального интервала запросов:
let lastRequestTime = 0;
function canRequest() {
const now = Date.now();
if (now - lastRequestTime < 500) return false;
lastRequestTime = now;
return true;
}
onSearch: (query) => {
if (!canRequest()) return;
fetch(`/api/search?q=${query}`)
.then(res => res.json())
.then(data => slimSelect.setData(data));
}
Такая защита предотвращает перегрузку backend при активном вводе.
При быстром вводе предыдущие запросы становятся неактуальными и должны быть отменены:
let controller;
function search(query) {
if (controller) {
controller.abort();
}
controller = new AbortController();
fetch(`/api/search?q=${query}`, {
signal: controller.signal
})
.then(res => res.json())
.then(data => {
slimSelect.setData(data);
})
.catch(() => {});
}
Этот механизм повышает стабильность интерфейса при высокой частоте обновлений данных.