最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Access to required fields with Yup - Stack Overflow

programmeradmin1浏览0评论

I use react-hook-form with yup to validate my forms.

I want to know all required fields of a schema to display some information in form (like '*' for required fields). We could achieve this with this line of code :

schema.describe().fields[field].tests.findIndex(({ name }) => name === 'required'

However, this code doesn't work for conditional validation.

Schema example :

const schema = yup.object().shape({
    email: yup
    .string()
    .email()
    .required(),

    isProfileRequired: yup
    .boolean(),

    profile:  yup
    .object()
    .when('isProfileRequired',{
        is: (isProfileRequired) => isProfileRequired,
        then:
            yup
            .object()
            .nullable()
            .required()
    })
})

Is there a way to retrieve this informations within the form ?

I use react-hook-form with yup to validate my forms.

I want to know all required fields of a schema to display some information in form (like '*' for required fields). We could achieve this with this line of code :

schema.describe().fields[field].tests.findIndex(({ name }) => name === 'required'

However, this code doesn't work for conditional validation.

Schema example :

const schema = yup.object().shape({
    email: yup
    .string()
    .email()
    .required(),

    isProfileRequired: yup
    .boolean(),

    profile:  yup
    .object()
    .when('isProfileRequired',{
        is: (isProfileRequired) => isProfileRequired,
        then:
            yup
            .object()
            .nullable()
            .required()
    })
})

Is there a way to retrieve this informations within the form ?

Share Improve this question asked Oct 20, 2020 at 7:26 Sponky30Sponky30 631 silver badge4 bronze badges 1
  • 1 Also discussed in this issue – colinD Commented Mar 4, 2022 at 10:46
Add a comment  | 

5 Answers 5

Reset to default 7

There is actually no "nice" way to do it but this works:

function isRequired(field){
    return schema.fields[field]._exclusive.required || false 
}

Notice: schema.fields[field]._exclusive.required returns true if required or undefined.

Testing exclusiveTests instead of _exclusive worked for me.

const isRequired = 
validationSchema?.fields[aField.name]?.exclusiveTests?.required || false;

Based on this comment in the link that @colinD shared, this is working well for me.

const isFieldRequired = (validationSchema, id) =>
  validationSchema
    .describe()
    .fields[id].tests.some(({ name }) => name === 'required')

This checks if any test in a particular field has a name equal to 'required'. For example:

const validationSchema: AnyObject = object({
  username: string().required(),
  email: string().email().required(),
})

will produce a schema with fields that look like:

{
  username: {
    ...
    tests: [
      {name: 'required', ...}, // is required
    ]
  },
  email: {
    ...
    tests: [
      {name: 'email', ...},
      {name: 'required', ...}, // is required
    ]
  },
}

In yup 1.2.0, it seems the property to use is now the optional boolean on SchemaDescription.

This is a function that returns a Record<keyof T, bool> where T is the generic parameter of the schema, and the boolean is true if the field is marked as required, false otherwise.

import { ObjectSchema, SchemaDescription } from "yup";

type FormObject = Record<string, unknown>;

const getRequiredFields = <T extends FormObject>(
  schema: ObjectSchema<FormObject>
) => {
  const fields = schema.describe().fields as Record<keyof T, SchemaDescription>;

  return Object.entries(fields).reduce((newObj, [key, schemaDescription]) => {
    newObj[key as keyof T] = !schemaDescription.optional;
    return newObj;
  }, {} as Record<keyof T, boolean>);
};

Usage:

const schema = yup.object({
  name: yup.string().required(),
  otherField: yup.string().optional(),
  code: yup.number().required(),
});

const fields = getRequiredFields(schema);

// fields = {
//    name: true,
//    otherField: false,
//    code: true,
// }

I made a hook based on @colinD solution.

export const useIsFieldRequired = <T extends FormObject>(
  schema: ObjectSchema<T>,
) => {
  const getRequiredFields = () => {
    const fields = schema.describe().fields as Record<
      keyof T,
      SchemaDescription
    >;

    return Object.entries(fields).reduce(
      (newObj, [key, schemaDescription]) => {
        newObj[key as keyof T] = !schemaDescription.optional;
        return newObj;
      },
      {} as Record<keyof T, boolean>,
    );
  };

  const requiredFields = getRequiredFields();

  const isFieldRequired = (field: keyof T): boolean => {
    return requiredFields[field];
  };

  return {
    isFieldRequired,
  };
};

Usage:

  const { isFieldRequired } = useIsFieldRequired<FormValues>(schema);

  return (
    <input name="input-name" required={isFieldRequired('input-name'} />
  )

发布评论

评论列表(0)

  1. 暂无评论