How to validate input values โ€‹โ€‹using React.JS?

I have a simple form. All components and state are stored in the Page component. There are 2 display headers and 3 input fields. The first input must be text, and the second and third must be ints. When the user enters the wrong data type, I want the error message to appear next to the input field. My questions are about best practices in React.JS

Who decides what value really is? I believe that the only task of the input field is to return the value back to the component containing the state, so does this mean that only the page can determine if the value is valid?

How do I pop up? Should the page trigger a new boolean status element that will be passed through perp, which tells Adaptive_Input to detect an error message?

Jsfiddle

JS:

/** * @jsx React.DOM */ var Adaptive_Input = React.createClass({ handle_change: function(){ var new_text = this.refs.input.getDOMNode().value; this.props.on_Input_Change(new_text); }, render: function(){ return ( <div className='adaptive_placeholder_input_container'> <input className="adaptive_input" type="text" required="required" onChange= {this.handle_change} ref="input" ></input> <label className="adaptive_placeholder" alt={this.props.initial} placeholder={this.props.focused} ></label> </div> ); } }); var Form = React.createClass({ render: function(){ return ( <form> <Adaptive_Input initial={'Name Input'} focused={'Name Input'} on_Input_Change={this.props.handle_text_input} /> <Adaptive_Input initial={'Value 1'} focused={'Value 1'} on_Input_Change={this.props.handle_value_1_input} /> <Adaptive_Input initial={'Value 2'} focused={'Value 2'} on_Input_Change={this.props.handle_value_2_input} /> </form> ); } }); var Page = React.createClass({ getInitialState: function(){ return { Name : "No Name", Value_1 : '0', Value_2 : '0', Display_Value: '0' }; }, handle_text_input: function(new_text){ this.setState({ Name: new_text }); }, handle_value_1_input: function(new_value){ console.log("==="); var updated_display = parseInt(new_value) + parseInt(this.state.Value_2); updated_display = updated_display.toString(); this.setState({ Display_Value: updated_display }); }, handle_value_2_input: function(new_value){ var updated_display = parseInt(this.state.Value_1) + parseInt(new_value); updated_display = updated_display.toString(); this.setState({ Display_Value: updated_display }); }, render: function(){ return( <div> <h2>{this.state.Name}</h2> <h2>Value 1 + Value 2 = {this.state.Display_Value}</h2> <Form handle_text_input={this.handle_text_input} handle_value_1_input = {this.handle_value_1_input} handle_value_2_input = {this.handle_value_2_input} /> </div> ); } }); React.renderComponent(<Page />, document.body); 
+66
javascript input validation reactjs
Jun 03 '14 at 15:44
source share
8 answers

Firstly, here is an example that I will talk about below: http://jsbin.com/rixido/2/edit

How to validate input values โ€‹โ€‹using React.JS?

However you want to. The reagent is designed to render a data model. The data model must know what is valid or not. You can use Backbone models, JSON data, or whatever you want to represent data, and this is an error condition.

More specific:

The reaction is usually independent of your data. This is for rendering and event handling.

Following are the following rules:

  • Items
  • can change their state.
  • they cannot change the details.
  • they can call a callback that will change the top-level details.

How to decide whether something should be a pillar or a state? Consider this: ANY part of your application, besides a text field, wants to know that the value entered is bad? If not, make this condition. If so, then this should be support.

For example, if you need a separate view for rendering "You have 2 errors on this page." then your error should be known to the top-level data model.

Where should this error be?
If your application displayed Backbone models (for example), the model itself would have a validate () method and a validateError property that you could use. You could display other intelligent objects that could do the same. The reaction also suggests trying to keep the details to a minimum and generate the rest of the data. therefore, if you have a validator (e.g. https://github.com/flatiron/revalidator ), your checks can leak down and any component can check the details with the appropriate check to make sure it is valid.

It is largely up to you.

(I personally use Backbone models and render them in React. I have a warning error message that I show if there is an error somewhere describing the error.)

+79
Jun 12 '14 at 20:12
source share

You can use npm install --save redux-form

I am writing a simple email and will submit a button form that validates the email and submits the form. with the redux form, the form by default triggers event.preventDefault () in the html onSubmit action.

 import React, {Component} from 'react'; import {reduxForm} from 'redux-form'; class LoginForm extends Component { onSubmit(props) { //do your submit stuff } render() { const {fields: {email}, handleSubmit} = this.props; return ( <form onSubmit={handleSubmit(this.onSubmit.bind(this))}> <input type="text" placeholder="Email" className={`form-control ${email.touched && email.invalid ? 'has-error' : '' }`} {...email} /> <span className="text-help"> {email.touched ? email.error : ''} </span> <input type="submit"/> </form> ); } } function validation(values) { const errors = {}; const emailPattern = /(.+)@(.+){2,}\.(.+){2,}/; if (!emailPattern.test(values.email)) { errors.email = 'Enter a valid email'; } return errors; } LoginForm = reduxForm({ form: 'LoginForm', fields: ['email'], validate: validation }, null, null)(LoginForm); export default LoginForm; 
+10
May 12 '16 at 13:26
source share

I wrote This library , which allows you to wrap the components of a form element and allows you to define your validators in the format: -

 <Validation group="myGroup1" validators={[ { validator: (val) => !validator.isEmpty(val), errorMessage: "Cannot be left empty" },... }]}> <TextField value={this.state.value} className={styles.inputStyles} onChange={ (evt)=>{ console.log("you have typed: ", evt.target.value); } }/> </Validation> 
+3
Jan 18 '17 at 6:56 on
source share

Your jsfiddle is no longer working. I fixed this: http://jsfiddle.net/tkrotoff/bgC6E/40/ using the React 16 and ES6 classes.

 class Adaptive_Input extends React.Component { handle_change(e) { var new_text = e.currentTarget.value; this.props.on_Input_Change(new_text); } render() { return ( <div className="adaptive_placeholder_input_container"> <input className="adaptive_input" type="text" required="required" onChange={this.handle_change.bind(this)} /> <label className="adaptive_placeholder" alt={this.props.initial} placeholder={this.props.focused} /> </div> ); } } class Form extends React.Component { render() { return ( <form> <Adaptive_Input initial={'Name Input'} focused={'Name Input'} on_Input_Change={this.props.handle_text_input} /> <Adaptive_Input initial={'Value 1'} focused={'Value 1'} on_Input_Change={this.props.handle_value_1_input} /> <Adaptive_Input initial={'Value 2'} focused={'Value 2'} on_Input_Change={this.props.handle_value_2_input} /> </form> ); } } class Page extends React.Component { constructor(props) { super(props); this.state = { Name: 'No Name', Value_1: '0', Value_2: '0', Display_Value: '0' }; } handle_text_input(new_text) { this.setState({ Name: new_text }); } handle_value_1_input(new_value) { new_value = parseInt(new_value); var updated_display = new_value + parseInt(this.state.Value_2); updated_display = updated_display.toString(); this.setState({ Value_1: new_value, Display_Value: updated_display }); } handle_value_2_input(new_value) { new_value = parseInt(new_value); var updated_display = parseInt(this.state.Value_1) + new_value; updated_display = updated_display.toString(); this.setState({ Value_2: new_value, Display_Value: updated_display }); } render() { return( <div> <h2>{this.state.Name}</h2> <h2>Value 1 + Value 2 = {this.state.Display_Value}</h2> <Form handle_text_input={this.handle_text_input.bind(this)} handle_value_1_input={this.handle_value_1_input.bind(this)} handle_value_2_input={this.handle_value_2_input.bind(this)} /> </div> ); } } ReactDOM.render(<Page />, document.getElementById('app')); 

And now the same code has been cracked by validating the form thanks to this library: https://github.com/tkrotoff/react-form-with-constraints => http://jsfiddle.net/tkrotoff/k4qa4heg/

http://jsfiddle.net/tkrotoff/k4qa4heg/

 const { FormWithConstraints, FieldFeedbacks, FieldFeedback } = ReactFormWithConstraints; class Adaptive_Input extends React.Component { static contextTypes = { form: PropTypes.object.isRequired }; constructor(props) { super(props); this.state = { field: undefined }; this.fieldWillValidate = this.fieldWillValidate.bind(this); this.fieldDidValidate = this.fieldDidValidate.bind(this); } componentWillMount() { this.context.form.addFieldWillValidateEventListener(this.fieldWillValidate); this.context.form.addFieldDidValidateEventListener(this.fieldDidValidate); } componentWillUnmount() { this.context.form.removeFieldWillValidateEventListener(this.fieldWillValidate); this.context.form.removeFieldDidValidateEventListener(this.fieldDidValidate); } fieldWillValidate(fieldName) { if (fieldName === this.props.name) this.setState({field: undefined}); } fieldDidValidate(field) { if (field.name === this.props.name) this.setState({field}); } handle_change(e) { var new_text = e.currentTarget.value; this.props.on_Input_Change(e, new_text); } render() { const { field } = this.state; let className = 'adaptive_placeholder_input_container'; if (field !== undefined) { if (field.hasErrors()) className += ' error'; if (field.hasWarnings()) className += ' warning'; } return ( <div className={className}> <input type={this.props.type} name={this.props.name} className="adaptive_input" required onChange={this.handle_change.bind(this)} /> <label className="adaptive_placeholder" alt={this.props.initial} placeholder={this.props.focused} /> </div> ); } } class Form extends React.Component { constructor(props) { super(props); this.state = { Name: 'No Name', Value_1: '0', Value_2: '0', Display_Value: '0' }; } handle_text_input(e, new_text) { this.form.validateFields(e.currentTarget); this.setState({ Name: new_text }); } handle_value_1_input(e, new_value) { this.form.validateFields(e.currentTarget); if (this.form.isValid()) { new_value = parseInt(new_value); var updated_display = new_value + parseInt(this.state.Value_2); updated_display = updated_display.toString(); this.setState({ Value_1: new_value, Display_Value: updated_display }); } else { this.setState({ Display_Value: 'Error' }); } } handle_value_2_input(e, new_value) { this.form.validateFields(e.currentTarget); if (this.form.isValid()) { new_value = parseInt(new_value); var updated_display = parseInt(this.state.Value_1) + new_value; updated_display = updated_display.toString(); this.setState({ Value_2: new_value, Display_Value: updated_display }); } else { this.setState({ Display_Value: 'Error' }); } } render() { return( <div> <h2>Name: {this.state.Name}</h2> <h2>Value 1 + Value 2 = {this.state.Display_Value}</h2> <FormWithConstraints ref={form => this.form = form} noValidate> <Adaptive_Input type="text" name="name_input" initial={'Name Input'} focused={'Name Input'} on_Input_Change={this.handle_text_input.bind(this)} /> <FieldFeedbacks for="name_input"> <FieldFeedback when="*" error /> <FieldFeedback when={value => !/^\w+$/.test(value)} warning>Should only contain alphanumeric characters</FieldFeedback> </FieldFeedbacks> <Adaptive_Input type="number" name="value_1_input" initial={'Value 1'} focused={'Value 1'} on_Input_Change={this.handle_value_1_input.bind(this)} /> <FieldFeedbacks for="value_1_input"> <FieldFeedback when="*" /> </FieldFeedbacks> <Adaptive_Input type="number" name="value_2_input" initial={'Value 2'} focused={'Value 2'} on_Input_Change={this.handle_value_2_input.bind(this)} /> <FieldFeedbacks for="value_2_input"> <FieldFeedback when="*" /> </FieldFeedbacks> </FormWithConstraints> </div> ); } } ReactDOM.render(<Form />, document.getElementById('app')); 

The solution offered here is hacky as I tried to keep it close to the original jsfiddle. To validate the form correctly using form-constrained-response, check https://github.com/tkrotoff/react-form-with-constraints#examples

+3
May 29 '17 at 20:34
source share

Use onChange={this.handleChange.bind(this, "name") and value={this.state.fields["name"]} in the text input field and below to create a span element to display the error, see the Example below ,

 export default class Form extends Component { constructor(){ super() this.state ={ fields: { name:'', email: '', message: '' }, errors: {}, disabled : false } } handleValidation(){ let fields = this.state.fields; let errors = {}; let formIsValid = true; if(!fields["name"]){ formIsValid = false; errors["name"] = "Name field cannot be empty"; } if(typeof fields["name"] !== "undefined" && !fields["name"] === false){ if(!fields["name"].match(/^[a-zA-Z]+$/)){ formIsValid = false; errors["name"] = "Only letters"; } } if(!fields["email"]){ formIsValid = false; errors["email"] = "Email field cannot be empty"; } if(typeof fields["email"] !== "undefined" && !fields["email"] === false){ let lastAtPos = fields["email"].lastIndexOf('@'); let lastDotPos = fields["email"].lastIndexOf('.'); if (!(lastAtPos < lastDotPos && lastAtPos > 0 && fields["email"].indexOf('@@') === -1 && lastDotPos > 2 && (fields["email"].length - lastDotPos) > 2)) { formIsValid = false; errors["email"] = "Email is not valid"; } } if(!fields["message"]){ formIsValid = false; errors["message"] = " Message field cannot be empty"; } this.setState({errors: errors}); return formIsValid; } handleChange(field, e){ let fields = this.state.fields; fields[field] = e.target.value; this.setState({fields}); } handleSubmit(e){ e.preventDefault(); if(this.handleValidation()){ console.log('validation successful') }else{ console.log('validation failed') } } render(){ return ( <form onSubmit={this.handleSubmit.bind(this)} method="POST"> <div className="row"> <div className="col-25"> <label htmlFor="name">Name</label> </div> <div className="col-75"> <input type="text" placeholder="Enter Name" refs="name" onChange={this.handleChange.bind(this, "name")} value={this.state.fields["name"]}/> <span style={{color: "red"}}>{this.state.errors["name"]}</span> </div> </div> <div className="row"> <div className="col-25"> <label htmlFor="exampleInputEmail1">Email address</label> </div> <div className="col-75"> <input type="email" placeholder="Enter Email" refs="email" aria-describedby="emailHelp" onChange={this.handleChange.bind(this, "email")} value={this.state.fields["email"]}/> <span style={{color: "red"}}>{this.state.errors["email"]}</span> </div> </div> <div className="row"> <div className="col-25"> <label htmlFor="message">Message</label> </div> <div className="col-75"> <textarea type="text" placeholder="Enter Message" rows="5" refs="message" onChange={this.handleChange.bind(this, "message")} value={this.state.fields["message"]}></textarea> <span style={{color: "red"}}>{this.state.errors["message"]}</span> </div> </div> <div className="row"> <button type="submit" disabled={this.state.disabled}>{this.state.disabled ? 'Sending...' : 'Send'}</button> </div> </form> ) } } 
+1
Nov 04 '18 at 16:52
source share

I recently spent a week learning a lot of solutions to validate my forms in an application. I started with all the most careful, but could not find the one who worked as I expected. A few days later I was very upset until I found a very new and amazing plugin: https://github.com/kettanaito/react-advanced-form

The developer is very responsive, and his decision, after my research, deserves to be the most careful from my point of view. I hope this can help, and you will appreciate.

0
Dec 28 '17 at 22:27
source share

another transition to the same problem - form-container on npm

0
Mar 03 '18 at 23:52
source share

In the past, I used redux-form and formik, and recently React introduced the Hook, and I created a special hook for it. Please check it and see if this makes checking your form easier.

Github: https://github.com/bluebill1049/react-hook-form

Website: http://react-hook-form.now.sh

with this approach you no longer make controlled input either.

example below:

 import React from 'react' import useForm from 'react-hook-form' function App() { const { register, handleSubmit, errors } = useForm() // initialise the hook const onSubmit = (data) => { console.log(data) } // callback when validation pass return ( <form onSubmit={handleSubmit(onSubmit)}> <input name="firstname" ref={register} /> {/* register an input */} <input name="lastname" ref={register({ required: true })} /> {/* apply required validation */} {errors.lastname && 'Last name is required.'} {/* error message */} <input name="age" ref={register({ pattern: /\d+/ })} /> {/* apply a Refex validation */} {errors.age && 'Please enter number for age.'} {/* error message */} <input type="submit" /> </form> ) } 
0
Apr 16 '19 at 9:43
source share



All Articles