Skip to content
  1. Компоненты
  2. FetchIt
  3. Валидация
  4. Валидация с помощью yup

Валидация с помощью yup

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

Важно!

Валидация на стороне клиента небезопасна и должна быть реализована только для удобства пользователя.

Разметка формы

Здесь ничего необычного, кроме атрибута novalidate добавленного элементу формы. Он нужен для того, чтобы отключить встроенную в браузер валидацию.

modx
<form action="[[~[[*id]]]]" method="post" novalidate>
  <label> Имя
    <input type="text" name="name" value="[[+fi.name]]" />
    <span data-error="name">[[+fi.error.name]]</span>
  </label>
  <label> Возраст
    <input type="text" name="age" value="[[+fi.age]]" />
    <span data-error="age">[[+fi.error.age]]</span>
  </label>
  <button>Можно?</button>
</form>

Подключение библиотеки

Для простоты примера подключим её через CDN и воспользуемся импортом.

html
<script type="module">
  import * as yup from 'https://cdn.jsdelivr.net/npm/yup@1/+esm';
</script>

Обработчик

Приступим к самому главному, добавление обработчика на событие fetchit:before который и будет валидировать данные формы.

  1. Добавим обработчик на событие fetchit:before.

    html
    <script type="module">
      import * as yup from 'https://cdn.jsdelivr.net/npm/yup@1/+esm';
    
      document.addEventListener('fetchit:before', (e) => { 
    
      }); 
    </script>
  2. Получим ссылки на экземпляры классов FormData и FetchIt.

    html
    <script type="module">
      import * as yup from 'https://cdn.jsdelivr.net/npm/yup@1/+esm';
    
      document.addEventListener('fetchit:before', (e) => {
        const { formData, fetchit } = e.detail; 
      });
    </script>
  3. Преобразуем formData в простой объект.

    html
    <script type="module">
      import * as yup from 'https://cdn.jsdelivr.net/npm/yup@1/+esm';
    
      document.addEventListener('fetchit:before', (e) => {
        const { formData, fetchit } = e.detail;
        const fields = Object.fromEntries(formData.entries()); 
      });
    </script>
  4. Напишем схему по которой будет валидироваться наша форма и сразу же укажем сообщения об ошибках.

    Локализация

    Библиотека yup предоставляет несколько способов локализации текстов ошибок. Для примера мы выбрали самый простой.

    Узнать о всех возможностях можно в документации.

    html
    <script type="module">
      import * as yup from 'https://cdn.jsdelivr.net/npm/yup@1/+esm';
    
      document.addEventListener('fetchit:before', (e) => {
        const { formData, fetchit } = e.detail;
        const fields = Object.fromEntries(formData.entries());
    
        const formSchema = yup.object({ 
          name: yup
            .string() 
            .required('Введите своё имя'), 
          age: yup
            .number() 
            .required('Введите свой возраст') 
            .min(18, 'Вам должно быть 18 лет') 
            .integer() 
            .typeError('Поле должно быть числом'), 
        }); 
      });
    </script>
  5. Вызовем синхронной метод валидации validateSync() в блоке try..catch для того чтобы мы могли отлавливать неудачные попытки.

    Информация

    Параметр abortEarly отвечает за прерывание валидации при первой неудаче. А нам нужно валидировать все поля и поэтому укажем false.

    html
    <script type="module">
      import * as yup from 'https://cdn.jsdelivr.net/npm/yup@1/+esm';
    
      document.addEventListener('fetchit:before', (e) => {
        const { formData, fetchit } = e.detail;
        const fields = Object.fromEntries(formData.entries());
    
        const formSchema = yup.object({
          name: yup
            .string()
            .required('Введите своё имя'),
          age: yup
            .number()
            .required('Введите свой возраст')
            .min(18, 'Вам должно быть 18 лет')
            .integer()
            .typeError('Поле должно быть числом'),
        });
    
        try { 
          formSchema.validateSync(fields, { abortEarly: false }); 
        } catch (err) { 
    
        } 
      });
    </script>
  6. Теперь нас интересует блок catch, там мы и будем отлавливать все ошибки валидации и с помощью метода setError() экземпляра класса FetchIt устанавливать невалидное состояние полям. Также вызовем метод preventDefault() события для того, чтобы прервать отправку формы.

    html
    <script type="module">
      import * as yup from 'https://cdn.jsdelivr.net/npm/yup@1/+esm';
    
      document.addEventListener('fetchit:before', (e) => {
        const { formData, fetchit } = e.detail;
        const fields = Object.fromEntries(formData.entries());
    
        const formSchema = yup.object({
          name: yup
            .string()
            .required('Введите своё имя'),
          age: yup
            .number()
            .required('Введите свой возраст')
            .min(18, 'Вам должно быть 18 лет')
            .integer()
            .typeError('Поле должно быть числом'),
        });
    
        try {
          formSchema.validateSync(fields, { abortEarly: false });
        } catch (err) {
          e.preventDefault(); 
    
          for (const { path, message } of err.inner) { 
            fetchit.setError(path, message); 
          } 
        }
      });
    </script>
  7. Опционально можно показать всплывающее сообщение об ошибке. Примеры подключения популярных библиотек вы можете найти здесь.

    html
    <script type="module">
      import * as yup from 'https://cdn.jsdelivr.net/npm/yup@1/+esm';
    
      document.addEventListener('fetchit:before', (e) => {
        const { formData, fetchit } = e.detail;
        const fields = Object.fromEntries(formData.entries());
    
        const formSchema = yup.object({
          name: yup
            .string()
            .required('Введите своё имя'),
          age: yup
            .number()
            .required('Введите свой возраст')
            .min(18, 'Вам должно быть 18 лет')
            .integer()
            .typeError('Поле должно быть числом'),
        });
    
        try {
          formSchema.validateSync(fields, { abortEarly: false });
        } catch (err) {
          e.preventDefault();
    
          for (const { path, message } of err.inner) {
            fetchit.setError(path, message);
          }
    
          FetchIt.Message.error('Исправьте ошибки в форме'); 
        }
      });
    </script>

Вот и всё! После этих шагов мы получим валидацию с использованием библиотеки yup, но помните, на стороне клиента она небезопасна. И поэтому при вызове сниппета нужно воспользоваться средствами валидации FormIt или если вы используете собственный сниппет, то производить её в нём.

Пример вызова сниппета с валидацией FormIt:

modx
[[!FetchIt?
  &form=`form.tpl`
  &hooks=`email,FormItSaveForm`
  &validate=`name:required,age:required:isNumber:minValue=^18^`

  // Необязательные параметры
  &snippet=`FormIt`
  &formName=`Название формы`
  &emailSubject=`Тема письма`
]]
fenom
{'!FetchIt' | snippet : [
  'form' => 'form.tpl',
  'hooks' => 'email,FormItSaveForm',
  'validate' => 'name:required,age:required:isNumber:minValue=^18^',

  // Необязательные параметры
  'snippet' => 'FormIt',
  'formName' => 'Название формы',
  'emailSubject' => 'Тема письма',
]}

Со списком всех валидаторов FormIt можете ознакомиться на сайте документации компонента.