Skip to content
This repository has been archived by the owner on Aug 23, 2022. It is now read-only.

How to validate nested/deep models/values #510

Closed
tiagoefmoraes opened this issue Oct 31, 2016 · 3 comments
Closed

How to validate nested/deep models/values #510

tiagoefmoraes opened this issue Oct 31, 2016 · 3 comments

Comments

@tiagoefmoraes
Copy link
Contributor

I need to validate deep values of a model user.phones[].number.

Tried setting Form validators to

  • "phones.number": { required: (val) => !!val }
  • "phones[].number": { required: (val) => !!val }
  • and phones: { number: { required: (val) => !!val }}

but none worked.

const store = createStore(combineForms({
  user: {
    name: '',
    phones: [{id: 1, number: ''}, {id: 2, number: ''}]
  },
}), applyMiddleware(thunk, createLogger()));

And a form for the user:

      <Form
        model="user"
        validators={
          {
            name: { required: (val) => !!val },
            
            /// How to validate phone numbers?
            phones: { number: { required: (val) => !!val }},
          }
        }
        onSubmit={(vals) => this.handleSubmit(vals)}
      >
      ...
        <br />
        Phones:
        {this.props.user.phones.map((phone) => {
          return (
            <div key={phone.id}>
              phone #{phone.id}:
              <Control.text model={track(".phones[].number", {id: phone.id})}/>
              <Errors
                model={track(".phones[].number", {id: phone.id})}
                messages={{
                  required: "Phone Required!",
                }}
              />
            </div>
            )
        })}
        <br />
        
        <button>Submit!</button>
      </Form>

Working example: https://esnextb.in/?gist=5cb62ba0efa95ce18bd82709c33be6bf

Any way of doing this?

@davidkpiano
Copy link
Owner

Currently, you can only do something like this:

const required = (val) => !!val;

<Form model="user"
  validators={{
    phones: { required: (numbers) => numbers.every(required) }
  }}
>
// ... etc.

The above is not exactly a workaround, just a way to tell the user that they forgot to fill out one of the many phone numbers they have. That's why I'm marking this as an enhancement; ideally you should be able to do this:

const required = (val) => !!val;

<Form model="user"
  validators={{
    'phones[].number': { required }
  }}
>
// ... etc.

For a real workaround, you can always attach validators={{...}} to the actual <Control.text>.

@tiagoefmoraes
Copy link
Contributor Author

I found another workaround:

<Form model="user"
  validators={{
    'phones.0.number': { required }
  }}
>

A more automated aproch:

  render() {
    const required = (val) => !!val;
    const { phones } = this.props.user;
    const phoneNumbersValidators = phones.reduce(
      (validators, _, index) => {
        validators[`phones.${index}.number`] = { required };
        return validators;
      }, {});
    return (
      <Form model="user"
        validators={phoneNumbersValidators)}
      >

'phones[].number': { required } would be much better.

Thanks

@tiagoefmoraes
Copy link
Contributor Author

tiagoefmoraes commented Nov 17, 2016

@davidkpiano Thanks, working 'almost' perfect, when the form is submited it becomes invalid, added some tests on this branch: https://github.com/tiagoefmoraes/react-redux-form/tree/deep_validation_submit

I fixed, will open a PR soon

tiagoefmoraes added a commit to tiagoefmoraes/react-redux-form that referenced this issue Nov 17, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants