Search code examples
javascriptnode.jsreactjsformsvalidation

How do I add validation to the form in my React component?


My Contact page form is as follows,

<form name="contactform" onSubmit={this.contactSubmit.bind(this)}>
  <div className="col-md-6">
    <fieldset>
      <input ref="name" type="text" size="30" placeholder="Name"/>
      <br/>
      <input refs="email" type="text" size="30" placeholder="Email"/>
      <br/>
      <input refs="phone" type="text" size="30" placeholder="Phone"/>
      <br/>
      <input refs="address" type="text" size="30" placeholder="Address"/>
      <br/>
    </fieldset>
  </div>
  <div className="col-md-6">
    <fieldset>
      <textarea refs="message" cols="40" rows="20"
                className="comments" placeholder="Message"/>
    </fieldset>
  </div>
  <div className="col-md-12">
    <fieldset>
      <button className="btn btn-lg pro" id="submit"
              value="Submit">Send Message</button>
    </fieldset>
  </div>
</form>

Need to add validation for all fields. Can anyone help me to add validation in this react form?


Solution

  • You should avoid using refs, you can do it with onChange function.

    On every change, update the state for the changed field.

    Then you can easily check if that field is empty or whatever else you want.

    You could do something as follows :

    class Test extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          fields: {},
          errors: {},
        };
      }
    
      handleValidation() {
        let fields = this.state.fields;
        let errors = {};
        let formIsValid = true;
    
        //Name
        if (!fields["name"]) {
          formIsValid = false;
          errors["name"] = "Cannot be empty";
        }
    
        if (typeof fields["name"] !== "undefined") {
          if (!fields["name"].match(/^[a-zA-Z]+$/)) {
            formIsValid = false;
            errors["name"] = "Only letters";
          }
        }
    
        //Email
        if (!fields["email"]) {
          formIsValid = false;
          errors["email"] = "Cannot be empty";
        }
    
        if (typeof fields["email"] !== "undefined") {
          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";
          }
        }
    
        this.setState({ errors: errors });
        return formIsValid;
      }
    
      contactSubmit(e) {
        e.preventDefault();
    
        if (this.handleValidation()) {
          alert("Form submitted");
        } else {
          alert("Form has errors.");
        }
      }
    
      handleChange(field, e) {
        let fields = this.state.fields;
        fields[field] = e.target.value;
        this.setState({ fields });
      }
    
      render() {
        return (
          <div>
            <form
              name="contactform"
              className="contactform"
              onSubmit={this.contactSubmit.bind(this)}
            >
              <div className="col-md-6">
                <fieldset>
                  <input
                    ref="name"
                    type="text"
                    size="30"
                    placeholder="Name"
                    onChange={this.handleChange.bind(this, "name")}
                    value={this.state.fields["name"]}
                  />
                  <span style={{ color: "red" }}>{this.state.errors["name"]}</span>
                  <br />
                  <input
                    refs="email"
                    type="text"
                    size="30"
                    placeholder="Email"
                    onChange={this.handleChange.bind(this, "email")}
                    value={this.state.fields["email"]}
                  />
                  <span style={{ color: "red" }}>{this.state.errors["email"]}</span>
                  <br />
                  <input
                    refs="phone"
                    type="text"
                    size="30"
                    placeholder="Phone"
                    onChange={this.handleChange.bind(this, "phone")}
                    value={this.state.fields["phone"]}
                  />
                  <br />
                  <input
                    refs="address"
                    type="text"
                    size="30"
                    placeholder="Address"
                    onChange={this.handleChange.bind(this, "address")}
                    value={this.state.fields["address"]}
                  />
                  <br />
                </fieldset>
              </div>
            </form>
          </div>
        );
      }
    }
    
    React.render(<Test />, document.getElementById("container"));
        
    
    

    In this example I did the validation only for email and name, but you have an idea how to do it. For the rest you can do it self.

    There is maybe a better way, but you will get the idea.

    Here is fiddle.

    UPDATE (functional components)

    const App = () => {
        const [fields, setFields] = useState({});
        const [errors, setErrors] = useState({});
        
        const handleValidation = () => {
          const formFields = {...fields};
          const formErrors = {};
          let formIsValid = true;
      
          //Name
          if(!formFields["name"]){
            formIsValid = false;
            formErrors["name"] = "Cannot be empty";
          }
      
          if(typeof formFields["name"] !== "undefined"){
            if(!formFields["name"].match(/^[a-zA-Z]+$/)){
              formIsValid = false;
              formErrors["name"] = "Only letters";
            }       
          }
      
          //Email
          if(!formFields["email"]){
            formIsValid = false;
            formErrors["email"] = "Cannot be empty";
          }
      
          if(typeof formFields["email"] !== "undefined"){
            let lastAtPos = formFields["email"].lastIndexOf('@');
            let lastDotPos = formFields["email"].lastIndexOf('.');
      
            if (!(lastAtPos < lastDotPos && lastAtPos > 0 && formFields["email"].indexOf('@@') == -1 && lastDotPos > 2 && (fields["email"].length - lastDotPos) > 2)) {
              formIsValid = false;
              formFields["email"] = "Email is not valid";
            }
          }     
    
          setErrors(formErrors)
          return formIsValid;
        }
        
        const handleChange = (field, value) => {
          setFields({
            ...fields,
            [field]: value
          })
        }
        
        const contactSubmit = (e) => {
          e.preventDefault();
          if(handleValidation()){
            alert("Form submitted");
          }else{
            alert("Form has errors.")
          }
        }
        
        return (
          <form onSubmit= {e => contactSubmit(e)}>
            <div>
              <input type="text" placeholder="Name" onChange={e => handleChange('name', e.target.value)} value={fields["name"]}/>
              <span className="error">{errors["name"]}</span>
            </div>
            
            <div>
              <input type="text" placeholder="Email" onChange={e => handleChange('email', e.target.value)} value={fields["email"]}/>
              <span className="error">{errors["email"]}</span>
            </div>
          
            <button className="btn btn-lg pro" id="submit" value="Submit">Send Message</button>
          </form>
        )
    };
    
    export default App;