Валидация с помощью yup
Данный раздел посвящен примеру интеграции библиотеки yup для дополнительной валидации данных формы перед отправкой на сервер. Представим, что нам нужно обработать простую форму с двумя полями, имя и возраст.
Важно!
Валидация на стороне клиента небезопасна и должна быть реализована только для удобства пользователя.
Разметка формы
Здесь ничего необычного, кроме атрибута novalidate
добавленного элементу формы. Он нужен для того, чтобы отключить встроенную в браузер валидацию.
<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 и воспользуемся импортом.
<script type="module">
import * as yup from 'https://cdn.jsdelivr.net/npm/yup@1/+esm';
</script>
Обработчик
Приступим к самому главному, добавление обработчика на событие fetchit:before
который и будет валидировать данные формы.
Добавим обработчик на событие
fetchit:before
.html<script type="module"> import * as yup from 'https://cdn.jsdelivr.net/npm/yup@1/+esm'; document.addEventListener('fetchit:before', (e) => { }); </script>
Получим ссылки на экземпляры классов
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>
Преобразуем 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>
Напишем схему по которой будет валидироваться наша форма и сразу же укажем сообщения об ошибках.
Локализация
Библиотека 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>
Вызовем синхронной метод валидации
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>
Теперь нас интересует блок
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>
Опционально можно показать всплывающее сообщение об ошибке. Примеры подключения популярных библиотек вы можете найти здесь.
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:
[[!FetchIt?
&form=`form.tpl`
&hooks=`email,FormItSaveForm`
&validate=`name:required,age:required:isNumber:minValue=^18^`
// Необязательные параметры
&snippet=`FormIt`
&formName=`Название формы`
&emailSubject=`Тема письма`
]]
{'!FetchIt' | snippet : [
'form' => 'form.tpl',
'hooks' => 'email,FormItSaveForm',
'validate' => 'name:required,age:required:isNumber:minValue=^18^',
// Необязательные параметры
'snippet' => 'FormIt',
'formName' => 'Название формы',
'emailSubject' => 'Тема письма',
]}
Со списком всех валидаторов FormIt можете ознакомиться на сайте документации компонента.