Ext JS to React: Form Validations

   JavaScript
Ext JS to React: Form Validations

This is part of the Ext JS to React blog series. You can review the code from this article on the Ext JS to React Git repo.

Form validation creates input boundaries / requirements for data entry. Form validation in Ext JS is handled by normalizing the validation work within the form fields components. With HTML5’s form fields (IE10+), we can let the inputs handle much of the validation work for us. Let’s look at an example of how we might author a custom React field component to display the form fields’ validation messages in the UI.

Note: While not a requirement for React, this article’s code examples assume you’re starting with a starter app generated by create-react-app.

Custom Form Field

First, let’s define a custom Field class where the field type and other particular can be passed in or use a predefined default. We’ll also look at incorporating some layout help from the Pure CSS package.

npm install --save purecss

The Field class:

import React, { Component } from 'react';
import '../node_modules/purecss/build/base.css';
import '../node_modules/purecss/build/forms.css';
import './Field.css';

class Field extends Component {
  static defaultProps = {
    value: '',
    type: 'text'
  }
  state = {
    invalidMsg: null,
    value: this.props.value
  }

  render () {
    const {
      label,
      onChange
    } = this.props;
    const { value, invalidMsg } = this.state;
    const inputProps = {
      ...this.props,
      value,
      onChange: (e) => this.handleChange(e, onChange)
    };
    return (
      <div className="pure-control-group">
        <label>{label}
          <input {...inputProps} style={{minWidth: '200px'}} />
          {
            invalidMsg ? 
              <span className="pure-form-message-inline">{invalidMsg}</span> : 
            null
          }
        </label>
      </div>
    );
  }
  
  handleChange (e, onChange) {
    this.setState({
      value: e.target.value
    });
    this.validateField(e);
    if (onChange && typeof onChange === 'function') {
      onChange(e);
    }
  }
  validateField (e) {
    const { target } = e,
          { validity } = target,
          { valueMissing, valid } = validity;
    let   invalidMsg;
 
    if (valueMissing) {
      invalidMsg = 'This is a required field';
    } else if (!valid) {
      invalidMsg = this.props.invalidMsg || target.validationMessage;
    }
    this.setState({ invalidMsg });
  }
}

export default Field;

We can then use the Field component in our App view:

class App extends Component {
  render() {
    return (
      <div>
        <Field
          required
          name="test"
          label="required text field "
          onChange={(e) => console.log('change', e)}
        /><br/>
        <Field
          type="number"
          max={20}
          name="test"
          label="number field (20 max) "
          onChange={(e) => console.log('change', e)}
        />
      </div>
    )
  }
}

export default App;


Ext JS to React: Form Validations


Custom Form Field Explained

That’s a good chunk of code. Let’s break down what we’re doing here. At the top we have our imports, including React and the CSS we’ll use to style the form on the page. For this example, we’re using the Pure CSS library to add a little bit of styling / layout support for our form elements. You’ll see the Pure CSS classes used as className values in our component’s JSX returned from the render method. In addition, we’ll add a bit of styling in our own {appRoot}/src/Field.css file that will make our validation message red:

input:invalid + .pure-form-message-inline {
  color: #c61c06;
}


Custom Form Field Class Methods

handleChange

  • For each input change we’ll first set the value on our component state giving us our controlled component
  • Next, we’ll call our validateField method which will add the invalid message to the UI if applicable
  • Finally, we’ll call any onChange handler that may have been passed in as a prop when the field component was instantiated

validateField

  • Initially, we collect up a few variables
    • target is the <input> field element we’re validating
    • validity is the ValidityState object of the input field
    • valueMissing will be true if our field is a required field and has no value
    • valid is false if the input is invalid for any reason
  • If the field is required and missing a value we’ll display our own message, else we’ll display the validation message from the field itself
  • Finally, we set the validation message on the component’s state. This will cause the component to re-render and display the validation error if one was discovered.

render

  • First, we extract a number of const variables from the props and the state object to be used as values in our rendered elements
  • Next, the props passed in along with the id, value from the component’s state, and the onChange handler are added to a props object to be passed to the input field of our output JSX
  • Finally, we output our field’s HTML elements using the component’s state / props:
    • A wrapping div used to create rows of input elements (versus inline)
    • A label for our input field
    • The input element with the type passed in as a prop (defaults to type “text”)
    • The span used to display the validation message (only rendered if invalidMsg has been passed in or set by our component’s validateField method)

Wrap Up

The above custom validation solution leverages the HTML5 properties only available to select browsers. So, what if you need to support older browsers such as IE9 and before? Instead of reading from the fields’ built in validation messages / state you could add your own validation logic and messaging logic. The Joi package is a popular validation package that could be used in place of HTML5 validations in your React projects. React-form and Formik are two popular form packages which provide their own form field validation, allowing you to define the validation schema and error message for each form field.


This website uses cookies

These cookies are used to collect information about how you interact with our website and allow us to remember you. We use this information in order to improve and customize your browsing experience, and for analytics and metrics about our visitors both on this website and other media. To find out more about the cookies we use, see our Privacy Policy.

Please consent to the use of cookies before continuing to browse our site.

Like What You See?

Got any questions?


>