Open idealistic opened 8 years ago
I'll try to sketch an example of a way to do this. Basically you need the parent to control the children; make your children pure (defined fully by their props.)
In this way the state is controlled at the parent and the validation methods are passed to the children but bound to the parents. I'll put an example together tomorrow.
I need the state to be controlled at the children level. The reason is that the children can be re-used with any parent form and need to be self sufficient. The validation logic for the children need to exist in the children to avoid dealing with recreating the validation and state for the children every time they are reused with different parents.
Ok, in that case we have the issue of the parent having a getValidatorData method but the children having the data. This can be solved a few ways. Basically, you need a way for the parent to access or passed the data. Since you said the data is managed by the child then you could expose a method like getValue on the child that you can call from the parent.
A great reference to this solution can be found in the <Input />
component from react-bootstrap: https://github.com/react-bootstrap/react-bootstrap/blob/master/src/InputBase.js#L12
And the spec for the Input component can be found here: https://github.com/react-bootstrap/react-bootstrap/blob/master/test/InputSpec.js#L56
Well...now I'm thinking there may be a caveat here. Still looking for a better example.
componentDidMount: function() {
this.refs.input.getValue(); //yolo
},
render: function() {
return (
<form >
<Input ref="input" type="input" defaultValue="yolo"/>
</form>
);
That will only get the value, how can I force form validation onSubmit of the form from the parent form component while the validation logic is in the children (form input fields)?
In this example you pass the handleValidation down to the children and expose the state to the parent. Now you can call this.props.isValid()
before submit.
getValidatorData: function() {
return {
name: this.refs.name.getValue(),
};
},
render: function() {
return (
<form >
<Input ref="name" type="input" defaultValue="yolo" handleValidation={this.props.handleValidation('name')} />
</form>
);
}
Looks like I can call validate
on each component from the parent via refs
and it works.
Because each validate
is running asynchronously, I need to know when it is done. Thoughts?
var validForm = false;
children.map(
function (child) {
child.validate(function(error) {
validForm = false;
if(!error) {
validForm = true;
}
});
}
)
Maybe provide a simple parent child example so I can see exactly what your doing and advise more specifically.
But, if you need control flow on async actions, just wrap them in a promise and wait for them all to resolve. Bluebird has some simple ways to handle this scenario.
I'm interested in the answer too. Here is an example:
I have a form:
class Form extends Component {
constructor(props) {
super(props);
this.validatorTypes = {
name: Joi.string().alphanum().required().label('Name')
};
this.state = {
name: this.props.settings.name
};
}
getValidatorData() {
return this.state;
}
render {
return (
<form>
<input type="text" onBlur={this.handleValidation('name')} /><br />
<AuthenticationInput />
</form>
);
}
}
And another class:
class AuthenticationInput extends Component {
constructor(props) {
super(props);
this.state = {
username: '',
password: '',
};
this.validatorTypes = {
username: Joi.string().required(),
password: Joi.string().required()
};
}
getValidatorData() {
return this.state;
}
render() {
<input type="text" onBlur={this.handleValidation('username') /><br />
<input type="text" onBlur={this.handleValidation('password') />
}
}
AuthenticationInput
has its own logic to validate its inputs, it works and it's fine.
Form
does not know how AuthenticationInput
validation logic works, and it's fine.
But if I submit Form
, I want AuthenticationInput
validation logic to be triggered automatically, as it is an element of Form
.
I could reference the AuthenticationInput
with the ref
attribute and trigger its validation from the Form
submit handler as @idealistic suggested but it does not feel natural.
@RudthMael Your idea is good, but it doesn't validate if I don't put anything. Do you have any solution to fix it without using refs in parent?
@jurassix, What if every form field is its own react component/class. The joi validation happens inside each component. The parent component, i.e. the form, just adds each component. In this case, how do you check if the form is valid?
I tried calling
this.validate
from the form component but it is throwing undefined.