Валидация входящих данных

При работе с динамическими выпадающими списками ключевым аспектом становится контроль целостности данных, поступающих в компонент. В Slim Select входные данные формируются через массив объектов, загружаемых при инициализации или добавляемых в процессе выполнения.

Базовая структура элемента данных обычно включает:

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

Любое отклонение от ожидаемой структуры приводит к некорректному отображению списка, дублированию значений или невозможности корректного выбора.

Типовой контроль структуры реализуется через нормализацию входящего массива перед передачей в компонент:

function normalizeOptions(raw) {
  return raw
    .filter(item => item && typeof item === 'object')
    .map(item => ({
      text: String(item.text ?? '').trim(),
      value: String(item.value ?? '').trim(),
      disabled: Boolean(item.disabled),
      selected: Boolean(item.selected)
    }))
    .filter(item => item.text.length > 0 && item.value.length > 0);
}

Подобная предобработка исключает попадание неконсистентных элементов и снижает вероятность ошибок рендеринга.


Контроль уникальности значений

Одним из критичных аспектов является уникальность value. Slim Select использует это поле как ключ идентификации элемента, и любые дубликаты приводят к конфликтам состояния.

Контроль уникальности обычно выполняется на этапе подготовки данных:

function uniqueByValue(options) {
  const seen = new Set();
  return options.filter(item => {
    if (seen.has(item.value)) return false;
    seen.add(item.value);
    return true;
  });
}

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


Проверка допустимости значений при динамическом добавлении

Slim Select позволяет изменять список опций во время выполнения. В таких сценариях возникает необходимость валидации добавляемых элементов до их включения в список.

Основной принцип заключается в проверке соответствия бизнес-правилам до вызова методов обновления:

  • допустимость формата значения
  • отсутствие запрещённых символов
  • соответствие справочнику разрешённых значений
  • проверка длины строки

Пример фильтрации:

function isValidValue(value) {
  const str = String(value).trim();
  if (str.length < 2) return false;
  if (str.length > 50) return false;
  if (!/^[a-zA-Z0-9_-]+$/.test(str)) return false;
  return true;
}

Валидация при работе с внешними источниками данных

При загрузке данных через API основная проблема заключается в недоверенности к структуре ответа. Даже при строгом контракте API возможны:

  • отсутствующие поля
  • неожиданные типы данных
  • вложенные структуры вместо плоских значений
  • дублирование записей

Перед передачей данных в Slim Select выполняется этап трансформации:

async function fetchOptions(url) {
  const res = await fetch(url);
  const data = await res.json();

  if (!Array.isArray(data)) return [];

  return normalizeOptions(data).filter(uniqueByValue);
}

Дополнительная проверка на уровне схемы ответа снижает вероятность некорректного состояния компонента.


Валидация состояния выбранных значений

В Slim Select выбранные значения могут задаваться программно через setSelected. В таких случаях требуется проверка соответствия значений текущему набору опций.

Несоответствие приводит к состоянию «висящих» значений, которые не отображаются в списке, но присутствуют в модели.

Контроль осуществляется сравнением выбранных значений с допустимым множеством:

function validateSelected(values, options) {
  const allowed = new Set(options.map(o => o.value));
  return values.filter(v => allowed.has(v));
}

Подобная проверка особенно важна при восстановлении состояния формы из хранилища или URL-параметров.


Обработка обязательных полей

В сценариях интеграции Slim Select с формами HTML возникает необходимость контроля обязательности выбора.

Валидация строится вокруг проверки наличия хотя бы одного значения:

function isRequiredValid(selectedValues) {
  return Array.isArray(selectedValues) && selectedValues.length > 0;
}

При мультивыборе дополнительно вводятся ограничения:

  • минимальное количество выбранных элементов
  • максимальное количество выбранных элементов
function validateRange(values, min, max) {
  return values.length >= min && values.length <= max;
}

Ограничение выбора по бизнес-правилам

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

В таких случаях валидация выполняется на уровне фильтрации списка до инициализации Slim Select:

function filterByRule(options, context) {
  return options.filter(item => {
    if (context.role === 'guest') {
      return !item.restricted;
    }
    return true;
  });
}

Дополнительно применяется блокировка выбора через disabled, чтобы сохранить визуальную целостность списка.


Валидация при асинхронном поиске

При использовании режима поиска через сервер возникает необходимость проверки результатов на каждом этапе ввода запроса.

Основные проблемы:

  • устаревшие результаты (race condition)
  • подмена ответа
  • некорректные значения в результате поиска

Решение заключается в привязке ответа к текущему запросу:

let lastQueryId = 0;

async function search(query) {
  const queryId = ++lastQueryId;

  const res = await fetch(`/api/search?q=${query}`);
  const data = await res.json();

  if (queryId !== lastQueryId) return [];

  return normalizeOptions(data);
}

Такой механизм предотвращает внедрение устаревших данных в список.


Санитизация текстовых значений

Отображаемый текст в text может содержать потенциально опасные или некорректные символы, особенно при выводе данных из внешних источников.

Применяется очистка:

function sanitizeText(text) {
  return String(text)
    .replace(/</g, '')
    .replace(/>/g, '')
    .trim();
}

Дополнительно может применяться нормализация пробелов и удаление управляющих символов.


Проверка optgroup-структур

Slim Select поддерживает группировку опций. При работе с optgroup требуется отдельная валидация вложенных структур.

Ожидаемая форма:

  • группа содержит label
  • содержит массив options
  • каждый элемент соответствует базовой структуре
function validateGroups(groups) {
  return groups
    .filter(g => g && Array.isArray(g.options))
    .map(g => ({
      label: String(g.label ?? '').trim(),
      options: normalizeOptions(g.options)
    }))
    .filter(g => g.label.length > 0 && g.options.length > 0);
}

Согласование состояния UI и модели данных

Расхождение между визуальным состоянием и моделью данных часто возникает при внешнем изменении состояния формы.

Контроль выполняется через принудительную синхронизацию:

  • сверка выбранных значений
  • удаление недопустимых элементов
  • обновление отображения
function syncState(instance, options) {
  const values = instance.getSelected();
  const valid = validateSelected(values, options);

  instance.setSelected(valid);
}

Обработка ошибок валидации

Ошибочные состояния должны обрабатываться без разрушения компонента. Основной подход заключается в деградации до безопасного состояния:

  • очистка некорректных значений
  • возврат к дефолтному списку
  • блокировка взаимодействия при критических ошибках
function safeInit(instance, options) {
  try {
    instance.setData(options);
  } catch {
    instance.setData([]);
  }
}

Такой подход предотвращает каскадные сбои при некорректных данных.