Пишем простым языком о сложных технических процессах

FetchIt - Дополнительная валидация с помощью библиотеки yup

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

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

У нас есть возможность импортировать библиотеку из CDN. Но помните, в продакшене такой способ лучше не использовать.

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

Добавление обработчика

  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. В данном событии мы можем получить доступ к данным формы и экземпляру класса 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. Затем, напишем схему по которой будет валидироваться наша форма и сразу же укажем сообщения об ошибках.

    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>

    Как вы видите, мы указали, что наша схема должна быть объектом с ключами:

    • name - значение которого должно быть строкой и оно обязательное.
    • age - значение которого должно быть числом, оно обязательное, должно быть больше 18-ти и целым.

    Внимание

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

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

  5. Вызовем метод валидации validateSync() нашей схемы в блоке try..catch для того чтобы мы могли отлавливать неудачные попытки.

    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=`Тема письма`
]]

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

Спасибо всем за внимание!