Reputation: 96
I'm a bit new to react and I'm trying to implement a dynamic form with validation. where I get the input details from the backend and render the component according to that. All worked fine but when I tried to include form validation (when the user submitting the form I want to work the form validation) it didn't work at all. I tried with every solution on the web but didn't find anything to fix this issue. Can anyone give me help to fix this problem? Thanks!!
Here is my code
class Slider extends Component {
constructor(props) {
super(props)
const { providerConfigs } = this.props
this.state = {
hasError: false,
inputs: [....]
}
}
....
handleOnSubmit = () => {
this.setState({ hasError: false })
const { providerMappingActions: { addProvider }, history } = this.props;
const { inputs } = this.state;
inputs.forEach(input => {
if (input.isRequired && input.attributeValue.length === 0) {
this.setState({ hasError: true })
}
if (input.attributeOptionId == 5 && input.attributeValue.length !== 0) {
if (input.attributeValue.length !== 10) {
this.setState({ hasError: true })
}
}
})
if (!this.state.hasError) {
const attributes = inputs.map(input => {
return {
attributeName: input.attributeName,
attributeValue: input.attributeValue,
isRequired: input.isRequired,
attributeOptionId: input.attributeOptionId,
}
});
console.log(attributes)
this.resetInputs();
}
}
render() {
const { hasError, inputs } = this.state;
return (
<div>
<div >
<div >
....
</FormGroup>)
: (
<FormGroup key={input.attributeOptionId}>
<FormControl
name={input.attributeName}
type={this.checkType(input.fieldType)}
autoFocus={!input.value}
value={input.value}
onChange={(e) => { this.handleChange(e) }}
className={`${(hasError && input.isRequired && input.attributeValue.length === 0) ? 'validation-field-error' :
hasError && input.attributeOptionId === 5 && input.attributeValue != '' && input.attributeValue.length !== 10 ? 'validation-field-error' : ''}`}
/>
</FormGroup>)
}
</td>
</tr>
);
})
}
<tr>
<td colSpan={2} align='right'>
{
inputs.map(input => {
if (hasError && input.isRequired && input.attributeValue.length === 0) {
return <div
key={input.attributeOptionId}
>
<label className='validation-error-text'><b>{input.attributeName} is required!</b></label>
</div>
} else if (hasError && input.attributeOptionId == 5 && input.attributeValue != '' && input.attributeValue.length !== 10) {
return <div
key={input.attributeOptionId}
>
<label className='validation-error-text'><b>Insert valid {input.attributeName}!</b></label>
</div>
}
}
)
}
</td>
</tr>
</tbody>
</table>
<FormGroup>
<div >
<div style={{ paddingLeft: "20px", paddingRight: "20px" }}>
<button
...
</div>
</FormGroup>
</form>
</div>
</div>
</div>
</div >
)
}}
Please note that I have removed some of the code to increase readability.
Upvotes: 2
Views: 897
Reputation: 44880
setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall.
Reading the state immediately after setting it will not guarantee the results you expect. Refactor to a local variable and set the state only once at the end of the function:
handleOnSubmit = () => {
const hasError = false;
const { providerMappingActions: { addProvider }, history } = this.props;
const { inputs } = this.state;
inputs.forEach(input => {
if (input.isRequired && input.attributeValue.length === 0) {
hasError = true;
}
if (input.attributeOptionId == 5 && input.attributeValue.length !== 0) {
if (input.attributeValue.length !== 10) {
hasError = true;
}
}
})
if (!hasError) {
const attributes = inputs.map(input => {
return {
attributeName: input.attributeName,
attributeValue: input.attributeValue,
isRequired: input.isRequired,
attributeOptionId: input.attributeOptionId,
}
});
console.log(attributes)
this.resetInputs();
}
// Set the state only once at the end of the function, this will
// cause a re-render if the value changes.
this.setState({ hasError });
}
Upvotes: 2