Wojciech Brożonowicz
Wojciech Brożonowicz
3 min read

Categories

Tags

Form in React - example with validation

Below simple example of Form in React with validation. Some notes:

  • noValidate in “<form onSubmit={this.handleSubmit} noValidate>” turns off default html5 validation (We will use our own function for this)
  • componentDidUpdate() will be executed after every render (except the first one), We will use this to hide message after 5 seconds
  • setTimeout() take 2 arguments: function to execute and time of delay
  • if We specify htmlFor tag with the same name as input id (id=”name_input”), when user click label it will activate input
  • to render something only on error===true we use f.e. for passwd “{this.state.errors.passwd && something…}” - it will render something only when this.state.errors.passwd will be equal to true (error === true)
  import React, { Component } from 'react';
import './App.css';

class App extends Component {

  state = {
    username: '',
    email: '',
    passwd: '',
    checkbox_accepted: false,
    succes_message: '',  // text to show when validation is OK [after click submit button]

    errors: {
      username: false,
      email: false,
      passwd: false,
      checkbox_accepted: false,
    }
  }

  // messages will not be chenged, so there is no need to define them in state
  messages = {
    username_not_ok: 'Name is too short',
    email_not_ok: 'Missing @ in email',
    password_not_ok: 'Password should have 6 characters',
    checkbox_not_ok: 'Checkbox should be checked'
  }

  handleChange = (e) => {
    const name = e.target.name;
    const type = e.target.type;
    // check type of input and set state accordingly
    if (type === "text" || type === "password" || type === "email") {
      const value = e.target.value;
      this.setState({
        [name]: value  
      })
    } else if (type === "checkbox") {
      const checked = e.target.checked;
      this.setState({
        [name]: checked
      })
    }
  }

  handleSubmit = (e) => {
    e.preventDefault()  // prevent form from default submit

    const validation = this.formValidation()  // run validation function

    if (validation.form_ok) {
      // clear inputs when validation is ok (reset form)
      this.setState({
        username: '',
        email: '',
        passwd: '',
        checkbox_accepted: false,
        message: 'Form is OK',

        errors: {
          username: false,
          email: false,
          passwd: false,
          checkbox_accepted: false,
        }
      })
    } else {
      this.setState({
        // setup errors object, We have validation.username === true when it is OK, and error === true 
        // when there is error, so We have to use ! to reverse value
        errors: {
          username: !validation.username,
          email: !validation.email,
          passwd: !validation.password,
          checkbox_accepted: !validation.checkbox_accepted
        }
      })
    }
  }

  formValidation() { 
    // function that validate all inputs and return object with total state of form (form_ok = true when validation is ok) 
    // and state of each input (true or false, true if input is ok)
 
    let username = false;
    let email = false;
    let password = false;
    let checkbox_accepted = false;
    let form_ok = false;

    // if username should have more then 5 characters and not contain space
    // string.idexOf('argument') will return -1 if not find argument in string, or index of argument in string
    if (this.state.username.length > 5 && this.state.username.indexOf(' ') === -1) {
      username = true;
    }

    if (this.state.email.indexOf('@') !== -1) {
      email = true;
    }

    // password should have exactly 6 characters
    if (this.state.passwd.length === 6) {
      password = true;
    }

    // checkbox should be checked
    if (this.state.checkbox_accepted) {
      checkbox_accepted = true
    }
    
    // if all inputs are ok
    if (username && email && password && checkbox_accepted) {
      form_ok = true
    }

    return ({
      form_ok,
      username,
      email,
      password,
      checkbox_accepted
    })
  }

  // if succes message is not empty string, We will reset it after 5 seconds 
  componentDidUpdate() {
    if (this.state.succes_message !== '') {
      setTimeout(() => this.setState({
        message: ''
      }), 5000)
    }
  }

  render() {
    return (
      <div className="App">
        <form onSubmit={this.handleSubmit} noValidate>
          <label htmlFor="name_input">Name:
          <input type="text" id="name_input" name="username" value={this.state.username} onChange={this.handleChange} />
            {this.state.errors.username && <span>{this.messages.username_not_ok}</span>}
          </label>

          <label htmlFor="email_input">Email:
          <input type="email" id="email_input" name="email" value={this.state.email} onChange={this.handleChange} />
            {this.state.errors.email && <span>{this.messages.email_not_ok}</span>}
          </label>

          <label htmlFor="password_input">Password:
          <input type="password" id="password_input" name="passwd" value={this.state.passwd} onChange={this.handleChange} />
            {this.state.errors.passwd && <span>{this.messages.password_not_ok}</span>}
          </label>
          <label htmlFor="accept_checkbox">
            <input type="checkbox" id="accept_checkbox" name="checkbox_accepted" checked={this.state.checkbox_accepted} onChange={this.handleChange} /> I accept
          </label>
          {this.state.errors.checkbox_accepted && <span>{this.messages.checkbox_not_ok}</span>}
          <button>Submit</button>
        </form>
        {this.state.succes_message && <h3>{this.state.succes_message}</h3>}
      </div>
    );
  }
}

export default App;

That’s all!