jquense / react-formal

Sophisticated HTML form management for React
http://jquense.github.io/react-formal
MIT License
526 stars 52 forks source link

DropDownList correct yup schema definition? #148

Closed IWCollege-AaronBentley closed 6 years ago

IWCollege-AaronBentley commented 6 years ago

Hey everybody 👋

I'm adding a communications option a form (Yes/No options, required) and I'm trying to figure out the correct schema for SelectList (using react-formal-inputs). Here's hoping someone can shed light on what I'm doing wrong here?!

I have the following form field component:

<Form.Field
    type="selectlist"
    name="contactPermission" />

And here's my (failed) attempts at creating the correct schema model for this field:

Using bool()

contactPermission: yup
    .boolean()
    .oneOf([true, false])
    .required('Please indicate your communications preference'),

Using array of bool()'s

contactPermission: yup.array().of(yup.object({
    yes: yup.boolean().oneOf([true]),
    no: yup.boolean().oneOf([false])
}))
.required('Please indicate your communications preference'),

Using array of objects (string values)

contactPermission: yup
    .array()
    .of(
        yup.object({
            yes: yup
                .string()
                .default('Yes')
        }),
        yup.object({
            no: yup
                .string()
                .default('No')
        })
    )
    .required('Please indicate your communications preference'),

All my above efforts so far have either yielded schema errors or a contactPermission type error.

I've been stuck on this for a while now 😐 Any tips or links to help me with this would be much appreciated.

Thanks in advance,

Aaron 😀

jquense commented 6 years ago

The SelecteList functions philosophically like a multiselect (for checkboxes) or a dropdown list (for radios). Which means it gives you an array of the selected values. If your values are permissions i'd make the the schema an array of your permission types: array().of(string().oneOf(['canEmail', 'canText', 'canShowUpAtMyHome'])

then the Selectlist is: <Field type='selectlist' multiple data={arrayOfAllPossiblePermisions} /> as you select or deselect values the value of the field will be the checked ones.

IWCollege-AaronBentley commented 6 years ago

Thank you for the swift reply @jquense 👍

I have implemented your given example to better understand how the yup schema is bound to validation, however, I'm not looking for multiple user selections, simply 'Yes' or 'No' options.

When I comment out the 'multiple' property from the Form Field (selectlist)...

<Form.Field
    // multiple
    type="selectlist"
    data={['Yes', 'canText', 'canShowUpAtMyHome']}
    name="contactPermission" />

... I get the following errors:

contactPermission must be a `array` type, but the final value was: `null` (cast from the value `"canShowUpAtMyHome"`). If "null" is intended as an empty value be sure to mark the schema as `.nullable()`

Perhaps I would be better suited using 'dropdownlist' in this instance? In which case I'm assuming my schema wouldn't need to be altered?

jquense commented 6 years ago

In the single case the value of permission isn't an array right? its a single enum string value so the schema for contactPermission should just be string().oneOf(['canEmail', 'canText', 'canShowUpAtMyHome'].

Think of the type of value the input represents, checkbox represent multiple selected values, and radio buttons represent one specific value. the options to chose from are outside the schema, specific only to the input.

IWCollege-AaronBentley commented 6 years ago

Thanks for your help @jquense, I think I've got it now. Bonus thanks for taking the time to explain the different use cases for enums and arrays too.

Should anyone else be looking for similar functionality, here's my code, trimmed for brevity:

Schema

contactPermission: yup
        .string()
        .oneOf(['Yes', 'No'])
        .required('Please indicate your communications preference')

Form Field

<Form.Field
    type="dropdownlist"
    data={['Yes', 'No']}
    name="contactPermission" />

Output screen shot 2018-03-27 at 14 26 43

IWCollege-AaronBentley commented 6 years ago

I've updated the issue title to better reflect the desired outcome and example code.

jquense commented 6 years ago

FYI if you really only have two options I'd do it like this:

contactPermission: yup
        .bool()
        .required('Please indicate your communications preference')
<Form.Field name="contactPermission">Can we contact you?</Form.Field>
EfstathiadisDimitris commented 5 years ago

What if you have more than 2 options though? If I have a list of items, coming from the backend asynchronously, how can I access that? I tried a few variations, but they don't seem to work.

I am using React-Select along with Yup and Formik. Any idea how am I going to accomplish that??

beipym commented 4 years ago

The SelecteList functions philosophically like a multiselect (for checkboxes) or a dropdown list (for radios). Which means it gives you an array of the selected values. If your values are permissions i'd make the the schema an array of your permission types: array().of(string().oneOf(['canEmail', 'canText', 'canShowUpAtMyHome'])

then the Selectlist is: <Field type='selectlist' multiple data={arrayOfAllPossiblePermisions} /> as you select or deselect values the value of the field will be the checked ones.

could you please help me with enums validation then?