[FetchIt] - Дополнительная валидация с помощью библиотеки yup
В данной заметке я расскажу как подружить компонент FetchIt с популярной библиотекой yup и реализовать дополнительную валидацию на стороне клиента.
Допустим, что нам необходимо обработать несложную форму с двумя полями, имя и возраст. И логика будет заключаться в том, если пользователь указывает свой возраст и он оказывается ниже 18-ти то мы не дадим отправить форму и покажем сообщение.
У нас есть возможность импортировать библиотеку из CDN. Но помните, в продакшене такой способ лучше не использовать.
1. Добавим обработчик на событие fetchit:before.
2. В данном событии мы можем получить доступ к данным формы и экземпляру класса FetchIt и именно это нам нужно сделать.
3. Теперь нам необходимо преобразовать formData в обычный объект.
4. Затем, напишем схему по которой будет валидироваться наша форма и сразу же укажем сообщения об ошибках.
Как вы видите, мы указали, что наша схема должна быть объектом с ключами:
Узнать о всех возможностях можно в документации.
5. Вызовем метод валидации validateSync() нашей схемы в блоке try..catch для того чтобы мы могли отлавливать неудачные попытки.
6. Затем обратим внимание на блок catch, т.к. там мы и будем отлавливать все ошибки валидации и с помощью метода setError() экземпляра класса FetchIt устанавливать невалидное состояние полям. Также вызовем метод preventDefault() события для того, чтобы прервать отправку формы.
7. Также по желанию вы можете показать всплывающее сообщение об ошибке и делается это очень просто.
Вот и всё! После этих шагов мы получим валидацию с использованием библиотеки yup, но помните, на стороне клиента она небезопасна. И поэтому при вызове сниппета нужно воспользоваться средствами валидации FormIt или если вы используете собственный сниппет, то производить её в нём.
Пример вызова сниппета с валидацией FormIt:
Вы сможете сейчас скачать бесплатно компонент с modstore.pro и modx.com с последними фиксами.
Всем мира и спасибо за внимание!
Документация
Репозиторий на GitHub
☕ Угостить чашкой кофе
Допустим, что нам необходимо обработать несложную форму с двумя полями, имя и возраст. И логика будет заключаться в том, если пользователь указывает свой возраст и он оказывается ниже 18-ти то мы не дадим отправить форму и покажем сообщение.
Подключение библиотеки
У нас есть возможность импортировать библиотеку из CDN. Но помните, в продакшене такой способ лучше не использовать.
<script type="module">
import * as yup from 'https://cdn.jsdelivr.net/npm/yup@1/+esm';
</script>
Добавление обработчика
1. Добавим обработчик на событие fetchit:before.
<script type="module">
import * as yup from 'https://cdn.jsdelivr.net/npm/yup@1/+esm';
document.addEventListener('fetchit:before', (e) => {
});
</script>
2. В данном событии мы можем получить доступ к данным формы и экземпляру класса FetchIt и именно это нам нужно сделать.
<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 в обычный объект.
<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. Затем, напишем схему по которой будет валидироваться наша форма и сразу же укажем сообщения об ошибках.
<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-ти и целым.
Узнать о всех возможностях можно в документации.
5. Вызовем метод валидации validateSync() нашей схемы в блоке try..catch для того чтобы мы могли отлавливать неудачные попытки.
<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() события для того, чтобы прервать отправку формы.
<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. Также по желанию вы можете показать всплывающее сообщение об ошибке и делается это очень просто.
<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=`Тема письма`
]]
Вы сможете сейчас скачать бесплатно компонент с modstore.pro и modx.com с последними фиксами.
Всем мира и спасибо за внимание!
Документация
Репозиторий на GitHub
☕ Угостить чашкой кофе
Комментарии: 15
Кстати, тут меня в комментариях @Лёша спросил про возможность показа сообщения в самой форме и я показал как это можно реализовать, но дело в том, что такая возможность была в альфа версии компонента, но я потом убрал такой функционал из коробки. Если проявите интерес, то я могу вернуть его.
Подскажите пожалуйста, если форма подгружается после инициализации FetchIt, например модалку(с вызовом сниппета FetchIt) подгружаю по надобности, как на форму в модалке «инициализировать» FetchIt?
Если коротко, то так:
Но проблема в том, что конфиг генерируется во время рендера страницы. Так уж задумано. Я подумаю как можно облегчить такие задачи в будущем
const fetchitInstance = new FetchIt(form: HTMLFormElement, config: {
action: string,
assetsUrl: string,
actionUrl: string,
inputInvalidClass: string,
customInvalidClass: string,
clearFieldsOnSuccess: boolean,
pageId: number,
});
// или
FetchIt.create(config: {
action: string,
assetsUrl: string,
actionUrl: string,
inputInvalidClass: string,
customInvalidClass: string,
clearFieldsOnSuccess: boolean,
pageId: number,
});
Но проблема в том, что конфиг генерируется во время рендера страницы. Так уж задумано. Я подумаю как можно облегчить такие задачи в будущем
Спасибо, «кастомно» получилось
if (FetchIt === undefined){
D.querySelector('head').append('<script src="/assets/components/fetchit/js/fetchit.js" defer=""></script>');
}
if(!empty(FetchIt)){
let a = D.querySelector(".modalTmp").querySelector('form').getAttribute('data-fetchit')
FetchIt.create({
action: a,
assetsUrl: "/assets/components/fetchit/",
actionUrl: "/assets/components/fetchit/action.php",
inputInvalidClass: "is-invalid",
customInvalidClass: "",
clearFieldsOnSuccess: true,
pageId: hashp,
});
}
Пожалуйста
1. Помни, это может поменяться, обращай внимания на обновления FetchIt
2. Пиши так:
1. Помни, это может поменяться, обращай внимания на обновления FetchIt
2. Пиши так:
let a = D.querySelector('.modalTmp form').getAttribute('data-fetchit')
// или
let a = D.querySelector('.modalTmp form').dataset.fetchit
буду следить (особенно жду эту фичу с дозагрузкой), понравился компонент, и сам начал пользоваться fetch в скриптах
Js ванилу не так давно начал, поэтому такие огрехи встречаются :)
Js ванилу не так давно начал, поэтому такие огрехи встречаются :)
let a = D.querySelector('.modalTmp form').getAttribute('data-fetchit')
а что за объект D к которому вы обращаетесь?
Это что какой-то поддерживаемый синоним объекта document?
Это что какой-то поддерживаемый синоним объекта document?
Обыкновенная переменная со ссылкой на объект document:
Не знаю зачем ему она, видимо для того чтобы писать короче
var D = document;
let D = document;
const D = document;
Не знаю зачем ему она, видимо для того чтобы писать короче
Все верно D = document; и да, чтобы писать короче.
А рекапча поддерживается?
Сам пользуюсь сниппетом, который аяксом обновляет чанк (на самом деле нет, это кастомный блок для zoomx, но так понятнее). И формы можно отправлять через formit, и фильтры делать. Не планируете расширять функционал, чтоб можно было чанки загружать? Название как раз к этому располагает) Мне самому не нужно, но думаю многим пригодится, пару раз видел тут, какие люди костыли городят для такого
Сам пользуюсь сниппетом, который аяксом обновляет чанк (на самом деле нет, это кастомный блок для zoomx, но так понятнее). И формы можно отправлять через formit, и фильтры делать. Не планируете расширять функционал, чтоб можно было чанки загружать? Название как раз к этому располагает) Мне самому не нужно, но думаю многим пригодится, пару раз видел тут, какие люди костыли городят для такого
А рекапча поддерживается?На данный момент можно использовать компонент reCaptchaV3, он отработает также как и с AjaxForm.
Не планируете расширять функционал, чтоб можно было чанки загружать?Пока в планах такого нет, но всё может изменится
@Баха Волков А с MODX 3 пока не работает?
На данный момент можно установить вручную скачав отсюда, не будут работать только файловые чанки.
Уже сделал. Сейчас тестирую. С чанками у Ajaxform вроде аналогичная ситуация
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.