admin管理员组

文章数量:1404624

Take for example an HTML form that collects the details of a person.

Note: Code snippets are simplified and do not match up with the screenshot exactly. Also, code snippets are written using Yup, which is a very similar library to Joi that targets the browser rather than NodeJS.

In order to submit the form, I want to run validations on the address fields and make them required, but only if the user has partially filled out the address section. As a whole, I want to make the address details optional.

Here is a simplified version of my PersonSchema...

import { object, string, number } from 'yup'

const PersonSchema = object().shape({
  name: string().required(),
  age: number()
    .positive()
    .integer()
    .required(),
  address: AddressSchema
})

Defining AddressSchema in this way does not work because the fields are always required...

const AddressSchema = object().shape({
  street: string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required(),
  city: string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required(),
  state: string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required()
})

And here was my attempt to make address fields dependent on the presence of other address fields, but this does not work because you run into circular dependency issues...

const AddressSchema = object().shape({
  street: string()
    .when(['city', 'state'], {
      is: (city, state) => city || state,
      then: string()
        .min(2, 'Too Short!')
        .max(50, 'Too Long!')
        .required(),
      otherwise: string()
    }),
  city: string()
    .when(['street', 'state'], {
      is: (street, state) => street || state,
      then: string()
        .min(2, 'Too Short!')
        .max(50, 'Too Long!')
        .required(),
      otherwise: string()
    }),
  state: string()
    .when(['street', 'city'], {
      is: (street, city) => street || city,
      then: string()
        .min(2, 'Too Short!')
        .max(50, 'Too Long!')
        .required(),
      otherwise: string()
    })
})

Take for example an HTML form that collects the details of a person.

Note: Code snippets are simplified and do not match up with the screenshot exactly. Also, code snippets are written using Yup, which is a very similar library to Joi that targets the browser rather than NodeJS.

In order to submit the form, I want to run validations on the address fields and make them required, but only if the user has partially filled out the address section. As a whole, I want to make the address details optional.

Here is a simplified version of my PersonSchema...

import { object, string, number } from 'yup'

const PersonSchema = object().shape({
  name: string().required(),
  age: number()
    .positive()
    .integer()
    .required(),
  address: AddressSchema
})

Defining AddressSchema in this way does not work because the fields are always required...

const AddressSchema = object().shape({
  street: string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required(),
  city: string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required(),
  state: string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required()
})

And here was my attempt to make address fields dependent on the presence of other address fields, but this does not work because you run into circular dependency issues...

const AddressSchema = object().shape({
  street: string()
    .when(['city', 'state'], {
      is: (city, state) => city || state,
      then: string()
        .min(2, 'Too Short!')
        .max(50, 'Too Long!')
        .required(),
      otherwise: string()
    }),
  city: string()
    .when(['street', 'state'], {
      is: (street, state) => street || state,
      then: string()
        .min(2, 'Too Short!')
        .max(50, 'Too Long!')
        .required(),
      otherwise: string()
    }),
  state: string()
    .when(['street', 'city'], {
      is: (street, city) => street || city,
      then: string()
        .min(2, 'Too Short!')
        .max(50, 'Too Long!')
        .required(),
      otherwise: string()
    })
})
Share Improve this question asked May 14, 2019 at 17:29 J. MunsonJ. Munson 2,9053 gold badges21 silver badges24 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 5

I needed the same optional address check: Rather than checking each field based against every other address field, just set a flag in your form/schema named something like 'addressStarted', then use that as your when trigger. The flag was an explicit choice by the user in my case, but it could just as easily be a hidden value; just toggle the value to true in every onChange handler (if you're using something like Formik), or even just an event listener on an element that contains all the address fields.

import { object, string, number } from 'yup'

const AddressSchema = object().shape({
  street: string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required(),
  city: string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required(),
  state: string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required()
})

const PersonSchema = object().shape({
  name: string().required(),
  age: number()
    .positive()
    .integer()
    .required(),
  addressStarted: Yup.boolean(),
  address: object().when('addressStarted', {
    is: true,
    then: AddressSchema,
    otherwise: object().notRequired()
  }),
})

本文标签: