Метод Zod.refine() не обеспечивает правило “одно из двух полей обязательно” в Vue 3

Вопрос или проблема

Я работаю над проектом 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) пусты, система не генерирует ошибки для обеих полей сразу.

Решение

Чтобы обеспечить правильную валидацию, убедитесь, что проверки будут правильно настроены и сообщения отображаются корректно. Вы можете воспользоваться следующим решением:

  1. Убедитесь, что вы добавили метод .refine() после определения всех полей, которые вы хотите валидировать.
  2. Правильно укажите путь к ошибкам, чтобы 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'],  // Укажите на оба поля
    }),

    // Шаг Ответственный...
];

Советы по отладке

  1. Проверьте, правильно ли вы инициируете валидацию вашей формы. Убедитесь, что ваша логика инициирования проверок работает корректно.
  2. Если вы используете библиотеку форм (например, react-hook-form или аналог), убедитесь, что ошибки корректно обрабатываются и отображаются.
  3. Напечатайте результат валидации, чтобы удостовериться, что ваше состояние данных передается верно:
console.log(formSchema.safeParse(formData)); // formData - ваши данные формы

Итог

С описанными изменениями ваша валидация должна работать так, как вы ожидаете. Если оба поля будут пустыми, отобразится сообщение ошибки для обоих полей. Убедитесь, что вы также обрабатываете и отображаете эти ошибки на уровне пользовательского интерфейса, чтобы пользователи могли это исправить. Если у вас еще есть вопросы, не стесняйтесь спрашивать.

Оцените материал
Добавить комментарий

Капча загружается...