I created the following form with validation using React:
- the data shall be validated at the time of input
- the data shall be validated again before submission
- all data all fields are mandatory and the data is valid
This program works, but I have the following problem:
I monitor the data check with onBlur, but when the user enters invalid data in the first field along with the error message for the first field ("Only letters"), an error message is displayed for the second field ("This field is a required").
How can I improve this my example to:
- at the time of input - an error message ('This field is required' or a particular message for an invalid data) was displayed only if the user touched a particular field
- if a button "Submit" was pressed - then error messages should be displayed near all fields with invalid data
My code:
const ErrorOutput = ({ error }) => <span>{error}</span>
class FormItem extends React.Component {
render() {
return (
<div>
<label>
{this.props.label}
</label>
<input
{...this.props.input}
/>
{this.props.error && <ErrorOutput error={this.props.error} />}
</div>
);
}
}
class App extends React.Component {
constructor(props){
super(props)
this.state = {
firstName: '',
telNo: '',
submit: false,
errors: {
firstName: '',
telNo: '',
},
invalid: false,
}
}
handleSubmit(e){
e.preventDefault()
if (this.validate()) {
console.log('Error!')
} else {
console.log('Success!')
}
}
validate = () => {
const { firstName, telNo } = this.state
const errors = {}
let invalid = false;
if (firstName === '') {
errors.firstName = 'first name is required'
invalid = true;
} else if (!firstName.match(/^[a-zA-Z]+$/)) {
errors.firstName = 'Letters only'
invalid = true;
}
if (telNo === '') {
errors.telNo = 'Phone is required'
invalid = true;
} else if (!telNo.match(/^[0-9]+$/)) {
errors.telNo = 'Numbers only'
invalid = true;
}
this.setState({
invalid,
errors,
})
return invalid;
}
render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<FormItem label='First name:' input={{
type: 'text',
name: 'firstName',
value: this.state.firstName,
onChange: e => this.setState({ firstName: e.target.value }),
onBlur: () => this.validate(),
}} error = {this.state.errors.firstName}
/>
<FormItem label='Phone number:' input={{
type: 'tel',
name: 'telNo',
value: this.state.telNo,
onChange: e => this.setState({ telNo: e.target.value }),
onBlur: () => this.validate(),
}} error = {this.state.errors.telNo}
/>
<button>
Submit
</button>
</form>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<body>
<div id="root"></div>
</body>