Вопрос или проблема
Я работаю над проектом Vite/Vue 3 и использую Zod для валидации форм. У меня есть форма с этими двумя полями:
descriptionActiEconomiques
и noga
Мне нужно обеспечить правило, что хотя бы одно из них должно быть заполнено. Если оба поля не заполнены, оба поля должны отображать ошибку с сообщением: “Одно из двух полей ‘Описание Экономической Деятельности’ или ‘NOGA’ обязательно.”
Моя полная схема выглядит так:
export const formSchema = [
// Этап Регистрация
z.object({
// Юридический адрес
typeInscription: z
.string({
required_error: 'Поле обязательно.',
}),
ide: z
.string({
required_error: 'Поле обязательно.',
})
.regex(/^CHE\d{9}$/, {
message: "Формат должен быть 'CHE' за которым следуют 9 цифр",
}),
nameUniteLocal: z
.string({
required_error: 'Поле обязательно.',
}),
formeJuridique: z
.string({
required_error: 'Поле обязательно.',
}),
pays: z
.string({
required_error: 'Поле обязательно.',
}),
langue: z
.string({
required_error: 'Поле обязательно.',
}),
descriptionActiEconomiques: z
.string()
.optional(),
noga: z
.string()
.optional(),
// Адрес
npa: z
.string({
required_error: 'Поле обязательно.',
})
.min(4, 'НПА недействителен.')
.max(4, 'НПА недействителен.'),
localite: z
.string({
required_error: 'Поле обязательно.',
}),
rue: z
.string({
required_error: 'Поле обязательно.',
}),
adresseUniteNumero: z
.string({
required_error: 'Поле обязательно.',
}),
uniteCasePostaleNumero: z
.string({
required_error: 'Поле обязательно.',
})
.optional(),
uniteCasePostaleNpa: z
.string({
required_error: 'Поле обязательно.',
})
.optional(),
uniteCasePostaleLocalite: z
.string({
required_error: 'Поле обязательно.',
})
.optional(),
// Контакт
numeroTelephone: z
.union([s1,s2]),
emailEntreprise: z
.string({
required_error: 'Поле обязательно.',
})
.email({
message: 'Недействительный Email.'
}),
// Другое
remarque: z
.string()
.optional(),
attachedFile: z
.string()
.optional()
}).refine((data) => data.descriptionActiEconomiques || data.noga, {
message: "Одно из двух полей 'Описание Экономической Деятельности' или 'NOGA' обязательно.",
path: ['descriptionActiEconomiques', 'noga'],
}),
// Этап Ответственный
z.object({
// Ответственный
responsablePersonneId: z
.string()
.optional(),
responsableSexe: z
.string()
.optional(),
responsablePrenom: z
.string({
required_error: 'Поле обязательно.',
}),
responsableNom: z
.string({
required_error: 'Поле обязательно.',
}),
// Контакт
responsableNumeroTelephone: z
.union([s1,s2]),
responsableEmail: z
.string({
required_error: 'Поле обязательно.',
})
.email({
message: 'Недействительный Email.'
}),
// Адрес
responsablePays: z
.string({
required_error: 'Поле обязательно.',
}),
responsableNpa: z
.string({
required_error: 'Поле обязательно.',
})
.min(4, 'НПА недействителен.')
.max(4, 'НПА недействителен.'),
responsableLocalite: z
.string({
required_error: 'Поле обязательно.',
}),
responsableRue: z
.string({
required_error: 'Поле обязательно.',
}),
responsableNumeroDeRue: z
.string({
required_error: 'Поле обязательно.',
}),
}),
]
Как вы видите, я попытался добавить:
.refine((data) => data.descriptionActiEconomiques || data.noga, {
message: "Одно из двух полей 'Описание Экономической Деятельности' или 'NOGA' обязательно.",
path: ['descriptionActiEconomiques', 'noga'],
})
Но это не сработало…
Ожидаемое Поведение
- Если оба поля descriptionActiEconomiques и noga оставлены пустыми, валидация должна завершиться неудачей, и ошибка должна появиться для обоих полей с сообщением: “Одно из двух полей ‘Описание Экономической Деятельности’ или ‘NOGA’ обязательно.”
Фактическое Поведение
- Сообщение об ошибке не отображается, когда оба поля пустые.
- Ошибок в консоли тоже нет.
Есть идеи, почему это правило валидации не работает, или как я могу это исправить?
Заранее спасибо!
Ответ или решение
Ваша проблема связана с тем, как используется метод .refine() в библиотеке Zod для проверки схемы формы. Давайте разберемся поэтапно, чтобы убедиться, что ваша валидация работает как задумано.
Причина проблемы
Ваш код для .refine() выглядит правильно, но проблема может заключаться в том, как Zod обрабатывает ошибки. В случае, если оба поля (descriptionActiEconomiques
и noga
) пусты, система не генерирует ошибки для обеих полей сразу.
Решение
Чтобы обеспечить правильную валидацию, убедитесь, что проверки будут правильно настроены и сообщения отображаются корректно. Вы можете воспользоваться следующим решением:
- Убедитесь, что вы добавили метод
.refine()
после определения всех полей, которые вы хотите валидировать. - Правильно укажите путь к ошибкам, чтобы Zod знал, к каким полям они относятся.
Исправленный код
Вот так может выглядеть ваш финальный код:
import { z } from 'zod';
export const formSchema = [
z.object({
// Текущие поля остаются без изменений...
descriptionActiEconomiques: z
.string()
.optional(),
noga: z
.string()
.optional(),
// Остальные поля...
}).refine(data => data.descriptionActiEconomiques || data.noga, {
message: "Лун дес двух шампов 'Description des Activités Économiques' или 'NOGA' ест рекиз.",
path: ['descriptionActiEconomiques', 'noga'], // Укажите на оба поля
}),
// Шаг Ответственный...
];
Советы по отладке
- Проверьте, правильно ли вы инициируете валидацию вашей формы. Убедитесь, что ваша логика инициирования проверок работает корректно.
- Если вы используете библиотеку форм (например,
react-hook-form
или аналог), убедитесь, что ошибки корректно обрабатываются и отображаются. - Напечатайте результат валидации, чтобы удостовериться, что ваше состояние данных передается верно:
console.log(formSchema.safeParse(formData)); // formData - ваши данные формы
Итог
С описанными изменениями ваша валидация должна работать так, как вы ожидаете. Если оба поля будут пустыми, отобразится сообщение ошибки для обоих полей. Убедитесь, что вы также обрабатываете и отображаете эти ошибки на уровне пользовательского интерфейса, чтобы пользователи могли это исправить. Если у вас еще есть вопросы, не стесняйтесь спрашивать.