Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create Yup nested object schema dynamically

For this "flat" object validation

const fields = [
  {label: 'Name', name: 'name', validation: yup.string().required()},
  {label: 'City', name: 'city', validation: yup.string().required()},
  {label: 'Phone', name: 'phone'},
]

I created createYupSchema function to get Yup schema object from fields.

const createYupSchema = (fields ) => {
  const schema = fields.reduce((schema, field) => {
      return field.validation 
      ? {...schema, [field.name]: field.validation} 
      : schema
  }, {})

  return yup.object().shape(schema)
}

The output is Yup object:

yup.object().shape({
  name: yup.string().required(),
  city: yup.string().required(),
}) 

But I would to have the possibility to use also nested object in fields

const fields = [
  {label: 'Name', name: 'name', validation: yup.string().required()},
  {label: 'Address', name: 'address.city', validation: yup.string().required()},
  {label: 'Phone', name: 'phone'},
]

So the Yup object should be:

yup.object().shape({
  name: yup.string().required(),
  address: yup.object().shape({
      city: yup.string().required()
  }),
}) 

Is it possibile to create this type of Yup object from fields?

like image 724
Webman Avatar asked Sep 13 '19 17:09

Webman


2 Answers

I resolved my question. Now createYupSchema works in this way

const createYupSchema = fields => {
  const schema = fields.reduce((schema, field) => {
    const isObject = field.name.indexOf(".") >= 0;

    if (!field.validation) {
      return schema;
    }

    if (!isObject) {
      return { ...schema, [field.name]: field.validation };
    }

    const reversePath = field.name.split(".").reverse();
    const currNestedObject = reversePath.slice(1).reduce((yupObj, path) => {
        return { [path]: yup.object().shape(yupObj) };
    }, {[reversePath [0]]: field.validation});

    return { ...schema, ...currNestedObject };
  }, {});

  return yup.object().shape(schema);
};
like image 193
Webman Avatar answered Nov 09 '22 14:11

Webman


I resolved my question, using the "lazy" method:

const validateSchema = Yup.object().shape({
    items: Yup.array().of(
        Yup.lazy((item) => {
            return Yup.object({
                itemName: Yup.string().test(
                    'validate',
                    'warning',
                    (value) => {
                        if (value && item.itemDescription) return true
                        if (!value && !item.itemDescription) return true
                        return false
                    }
                ),
                itemDescription: Yup.string().test(
                    'validate',
                    'warning',
                    (value) => {
                        if (value && item.itemName) return true
                        if (!value && !item.itemName) return true
                        return false
                    }
                ),
            })
        })
    ),
})
like image 1
Andrew Yurets Avatar answered Nov 09 '22 12:11

Andrew Yurets