Встроенная валидация

В основе поведения валидации в Slim Sel ect лежит принцип наследования стандартных возможностей HTML <select> с расширением за счёт JavaScript-обёртки. Библиотека не заменяет нативную модель валидации формы, а взаимодействует с ней, сохраняя совместимость с HTML5 constraint validation API.

Ключевой особенностью является то, что состояние валидности не хранится отдельно внутри библиотеки как самостоятельная система правил. Вместо этого используется синхронизация DOM-состояния оригинального <select> элемента и визуального слоя Slim Select. Это позволяет сохранять корректную работу с формами без необходимости внедрения внешнего валидатора.


Связь с HTML5 Constraint Validation API

Основой встроенной валидации выступает HTML5 механизм ограничений (constraint validation), который работает через свойства:

  • required
  • valueMissing
  • validity
  • checkValidity()
  • reportValidity()

Slim Select не переопределяет эти механизмы, а лишь отражает их состояние в кастомном интерфейсе.

При изменении значения через Slim Select фактически изменяется значение исходного <select>, что автоматически приводит к обновлению валидности формы.

Пример базовой интеграции:

<form id="form">
  <select id="country" required>
    <option value="">Выбор не выполнен</option>
    <option value="kz">Kazakhstan</option>
    <option value="de">Germany</option>
  </select>

  <button type="submit">Отправка</button>
</form>

<script>
  const select = document.getElementById('country');

  new SlimSelect({
    select: select
  });

  document.getElementById('form').addEventListener('submit', (e) => {
    if (!select.checkValidity()) {
      e.preventDefault();
      select.reportValidity();
    }
  });
</script>

В данном случае библиотека не вмешивается в логику проверки, а лишь обеспечивает корректное обновление значения.


Обязательные поля и поведение required

Наиболее частый сценарий встроенной валидации связан с атрибутом required. В Slim Select он обрабатывается через нативную проверку пустого значения.

Если у <select> присутствует required, то пустое значение считается недопустимым до момента выбора валидного option.

Особенности поведения:

  • пустой value="" считается невыбранным состоянием
  • при инициализации состояние сохраняется из DOM
  • визуальная часть Slim Select отображает текущее значение, но не влияет на constraint validation напрямую

Пример:

<select id="city" required>
  <option value="">--</option>
  <option value="almaty">Almaty</option>
  <option value="astana">Astana</option>
</select>

<script>
  new SlimSelect({
    select: '#city'
  });
</script>

При отправке формы, если значение не выбрано, браузер блокирует submit без необходимости дополнительного кода.


Валидация множественного выбора

При использовании multiple поведение валидации усложняется, поскольку стандарт HTML не предоставляет ограничений на минимальное или максимальное количество выбранных значений.

Slim Select не вводит встроенных атрибутов min или max, но предоставляет инфраструктуру для построения таких правил через контроль значения <select>.

Пример логики ограничения минимального количества:

<select id="tags" multiple>
  <option value="js">JavaScript</option>
  <option value="css">CSS</option>
  <option value="html">HTML</option>
  <option value="node">Node.js</option>
</select>

<script>
  const select = document.getElementById('tags');

  new SlimSelect({
    select: select
  });

  function validateMinSelection() {
    const values = Array.fr om(sel ect.selectedOptions).map(o => o.value);
    return values.length >= 2;
  }

  document.getElementById('form')?.addEventListener('submit', (e) => {
    if (!validateMinSelection()) {
      e.preventDefault();
      select.setCustomValidity('Необходимо выбрать минимум 2 значения');
      select.reportValidity();
    } else {
      select.setCustomValidity('');
    }
  });
</script>

Хотя setCustomValidity относится к DOM API, Slim Select обеспечивает актуальность выбранных значений без дополнительной синхронизации.


Управление состоянием через disabled options

Встроенная валидация часто опирается на состояние отдельных опций. Атрибут disabled играет важную роль, поскольку исключает option из списка допустимых значений.

В Slim Select disabled-элементы:

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

Пример:

<select id="plan">
  <option value="free">Free</option>
  <option value="pro" disabled>Pro (disabled)</option>
  <option value="enterprise">Enterprise</option>
</select>

<script>
  new SlimSelect({
    select: '#plan'
  });
</script>

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


Синхронизация DOM и визуального состояния

Ключевой принцип работы заключается в том, что Slim Select не является источником истины. Источником всегда остаётся <select>.

При каждом изменении:

  1. обновляется DOM значение <select>
  2. вызывается нативное событие change
  3. пересчитывается валидность формы
  4. обновляется визуальный компонент Slim Select

Такой подход исключает рассинхронизацию между интерфейсом и HTML-формой.

const select = document.querySelector('#lang');

const slim = new SlimSelect({
  select
});

select.addEventListener('change', () => {
  console.log(select.value);
  console.log(select.checkValidity());
});

Перехват изменений и пользовательская валидация

Дополнительный уровень контроля достигается через обработку событий изменения значения. Slim Select генерирует стандартное событие change, что позволяет внедрять произвольные правила.

Пример проверки запрещённых комбинаций:

const select = document.querySelector('#skills');

new SlimSelect({
  select
});

select.addEventListener('change', () => {
  const values = Array.fr om(select.selectedOptions).map(o => o.value);

  if (values.includes('node') && values.includes('php')) {
    select.setCustomValidity('Node.js и PHP не могут быть выбраны одновременно');
  } else {
    select.setCustomValidity('');
  }
});

Такой подход позволяет строить сложные бизнес-правила поверх стандартного select без модификации библиотеки.


Интеграция с формами и submit-процессом

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

Однако в некоторых сценариях требуется принудительная проверка:

const form = document.querySelector('#form');
const select = document.querySelector('#service');

new SlimSelect({
  select
});

form.addEventListener('submit', (e) => {
  if (!form.checkValidity()) {
    e.preventDefault();
    form.reportValidity();
  }
});

В этом случае Slim Select не участвует в логике submit напрямую, но обеспечивает корректное обновление значений, которые участвуют в проверке.


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

При динамическом обновлении списка <option> важно учитывать, что валидность пересчитывается браузером автоматически, но визуальный слой Slim Select требует синхронизации.

Пример добавления новых значений:

const select = document.querySelector('#dynamic');

const slim = new SlimSelect({
  select
});

function addOption(value, text) {
  const option = document.createElement('option');
  option.value = value;
  option.textContent = text;
  select.appendChild(option);

  // обновление состояния select
  select.dispatchEvent(new Event('change'));
}

При этом состояние required или disabled продолжает работать без дополнительных настроек.


Ограничения встроенной модели валидации

Встроенная модель валидации в Slim Select опирается исключительно на возможности HTML, что накладывает ряд ограничений:

  • отсутствует декларативная схема min/max выбора
  • нет встроенного механизма сложных зависимостей между полями
  • невозможна централизованная система правил внутри библиотеки
  • кастомные сообщения реализуются через DOM API, а не через Slim Select

Такая архитектура делает систему предсказуемой, но требует внешней логики для сложных сценариев.


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

При установке значения через JavaScript важно учитывать влияние на валидность:

const select = document.querySelector('#status');

new SlimSelect({
  select
});

select.value = 'active';
select.dispatchEvent(new Event('change'));

В этом случае:

  • обновляется значение <select>
  • пересчитывается validity
  • обновляется UI Slim Select

Если значение не входит в допустимые option, браузер считает поле невалидным, даже если UI отображает выбранное состояние.


Итоговые особенности поведения встроенной валидации

  • базируется на HTML5 constraint validation API
  • не содержит собственной системы правил
  • полностью синхронизирована с DOM <select>
  • поддерживает required, disabled и multiple через стандартные механизмы
  • расширяется через setCustomValidity и обработчики событий
  • зависит от корректной синхронизации изменения значений и событий формы