Ext JS to React: Form Fields

   JavaScript
Ext JS to React: Form Fields

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.

By this time in the Ext JS to React series you may find yourself asking, “So, is now a good time to talk about form fields?” It sure is! Forms are a primary way for end users to supply feedback through our web applications, so they’re used a lot in the real world. Ext JS includes a number of form fields within the framework designed to make form layouts, validation, and submission easier. Before getting into handling the user input, let’s first take a look at how to create the form fields themselves using React.

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.

Input / Textfield

Ext JS provides a number of text input fields that can be fairly easily replicated in React using the various input types. A number of these are HTML 5 and supported on IE10+ but will require a different strategy if your supported browser base is lower than IE10. The input field type is created using the xtype of “textfield”. Other input types such as “password”, “url”, and “search” have their own xtypes / classes: passwordfield (Ext.field.Password), urlfield (Ext.field.Url), and searchfield (Ext.field.Search). When defining forms in React, you can use the native HTML types:

import React, { Component } from 'react';
import './App.css';

class App extends Component {
  render() {
    return (
      <form className="login-form">
        <input type="text" /><br />
        <input type="password" /><br />
        <input type="url" /><br />
        <input type="search" /><br />
      </form>
    );
  }
}

export default App; 


Ext JS to React: Form Fields, Field



Note: A number of the Ext JS input field config options have HTML attribute counterparts that can be used when defining input fields in React. One attribute of note is the value. In plain HTML, <textarea> and <select><option> do not use value to set their initial value. However, React normalizes this for you, allowing all three input options to be initially set using a value="" prop.

You can review the sample code on the Git repo.

Textarea

A textarea with 4 rows in React:

import React from 'react';
import './App.css';

export default () => <textarea rows="4"/>; 


Ext JS to React: Form Fields, Text Area



You can review the sample code on the Git repo.

Selectfield

The Ext JS combobox (Ext.field.ComboBox) is somewhat of a mashup of the native <select> and <input> field. A combobox configured with editable: false is comparable to a <select> field. In React, you can return a select field with option elements for each eligible choice from the select component’s options array:

import React, { Component } from 'react';
import './App.css';

class App extends Component {
  state = {
    value: '_default'
  };
  options = ['Solids', 'Stripes']
  render() {
    return (
      <select
        value={this.state.value}
        onChange={e => this.handleSelectChange(e)}
      >
        {[
          <option disabled key="_default" value="_default">
            select one...
          </option>,
          ...this.options.map(
            item => (
              <option key={item} value={item.toLowerCase()}>{item}</option>
            )
          )
        ]}
      </select>
    );
  }
  handleSelectChange (e) {
    this.setState({
      value: e.target.value
    });
  }
}

export default App;

The above example introduces a couple of nuances. The onChange event handler serves a couple of purposes. First, without an onChange handler, when you define a field with a value=, the select field will be rendered as readonly. Second, the change handler sets the value of the select field via the React component’s internal state by having the value derived from the state initially.

Ext JS to React: Form Fields, Select


<select value={this.state.value} //...

This circular setup is what is known as a controlled component. It is the recommended path, as the value of the field is then settable by the user or any mechanism that has access to the component state. For information on “uncontrolled” components see React’s documentation.

You can review the sample code on the Git repo.

Combobox

To present a list of possible choices, but also allow any user input provided, you can omit the editable config option in the Ext JS example. To provide the same suggestion list, but still allow user input, have your React component return an <input> field using the list attribute along with a datalist (IE10+ and unsupported in Safari). This provides the added benefit of datalist filtering as the user types:

import React, { Component } from 'react';
import './App.css';

class App extends Component {
  state = {
    color: ''
  };
  options = ['Red', 'Blonde', 'Brown', 'Black']

  render() {
    return (
      <div>
        <input
          value={this.state.color}
          list="hair-color"
          onChange={e => this.handleChange(e)}
        />
        <datalist id="hair-color">
          {[this.options.map(
            item => <option key={item} value={item} />
          )]}
        </datalist>
      </div>
    );
  }

  handleChange(e) {
    this.setState({
      color: e.target.value
    });
  }
}

export default App;


Ext JS to React: Form Fields, Combo Box



You can review the sample code on the Git repo.

Range / Slider

The slider (Ext.slider.Single) field is comparable to the range field (IE10+) we’ll return from the React example. Let’s initialize the field with a value of 50, a minimum value of 0, a maximum value of 100, and an increment / step of 10.

import React, { Component } from 'react';
import './App.css';

class App extends Component {
 state = {
   value: 50
 };
 render() {
   return (
     <input
       onChange={e => this.handleChange(e)}
       type="range"
       value={this.state.value}
       min="0"
       max="100"
       step="10"
     />
   );
 }
 handleChange (e) {
   this.setState({
     value: e.target.value
   });
 }
}

export default App;


Ext JS to React: Form Fields, Slider



You can review the sample code on the Git repo.

Datefield

The datefield (Ext.field.Date) displays a calendar for easy selection of a day, month, and year. Displaying a calendar view for easy date selection is a bit less trivial in React than in Ext JS. You can use the input field of type date, but the implementation across browsers / platforms is incomplete. An example of the date input field in React is:

// npm install --save moment

import React, { Component } from 'react';
import moment from 'moment';

class App extends Component {
 state = {
   value: moment().format('YYYY-MM-DD')
 };
 render() {
   return <input
     type="date"
     value={this.state.value}
     onChange={e => this.handleChange(e)}
   />;
 }
 handleChange (e) {
   this.setState({
     value: e.target.value
   });
 }
}

export default App;


Ext JS to React: Form Fields, Date Field



The date type is not supported on IE or Safari. For additional cross-browser implementations, you may want to look at using a date field package like react-datepicker or react-dates Alternatively, you may want to consider a component library like kendo UI.

You can review the sample code on the Git repo.

Number / Spinner

In Ext JS there are two fields related to the input of numbers. The numberfield (Ext.field.Number) restricts the input to numeric entries only, while the spinnerfield (Ext.field.Spinner) adds up / down arrows in the field to enable users to increment and decrement the field value without explicitly entering a numeric value. An equivalent implementation of the spinner field (IE10+) in React would be:

import React, { Component } from 'react';

class App extends Component {
 state = {
   value: 50
 };
 render() {
   return <input
     type="number"
     value={this.state.value}
     onChange={e => this.handleChange(e)}
     step="10"
     min="0"
     max="100"
   />;
 }
 handleChange (e) {
   this.setState({
     value: e.target.value
   });
 }
}

export default App;


Ext JS to React: Form Fields, Number Field



You can review the sample code on the Git repo.

Radio

Radio fields (Ext.field.Radio) are defined with a shared name config with each field instance possessing a distinct value to pass on form submission. These are the same conventions used in HTML, as seen in the following React form with ‘red’, ‘blue’, and ‘green’ radio fields:

import React, { Component } from 'react';

class Radio extends Component {
 state = {
   checked: !!this.props.checked
 }
 render () {
   return <input
     type="radio"
     name={this.props.name}
     value={this.props.value}
     checked={this.state.checked}
     onChange={e => this.handleFieldChange(e)}
   />
 }
 handleFieldChange (e) {
   this.setState({
     checked: e.target.checked
   });
 }
}

export default Radio;

Our App class can now use the Radio class directly within a form:

import React, { Component } from 'react';
import Radio from './Radio';

class App extends Component {
 render () {
   const colorRadioName = 'color';
   return (
     <form>
       <label>
         Red
         <Radio name={colorRadioName} value="red" checked />
       </label>
       <br />
       <label>
         Blue
         <Radio name={colorRadioName} value="blue" />
       </label>
       <br />
       <label>
         Green
         <Radio name={colorRadioName} value="green" />
       </label>
     </form>
   );
 }
}

export default App;


Ext JS to React: Form Fields, Radio



Let’s talk a little about some of the other differences in this example. First, we’ve made a couple of allowances for the sake of brevity. We’ve left out the styling of the labels and inputs, and while normally each class would be defined in separate files, we’ve added both the radio component and the form to the same file. The radio component has been defined on its own since the type, change handler, and checked property will be the same across each radio instance. We then pass in the desired name, value, and checked value. The checked value passed (if at all) shows up on the radio component’s props object to then be set on the radio instance.

You can review the sample code on the Git repo.

Checkbox

Ext JS checkbox (Ext.field.Checkbox) fields are defined similar to radio fields, but have unique `name` configs. The React checkbox example is also very similar to our radiofield example where the name fields are unique per field:

import React, { Component } from 'react';

class Checkbox extends Component {
 state = {
   checked: !!this.props.checked
 }
 render () {
   return <input
     type="checkbox"
     name={this.props.name}
     value={this.props.value}
     checked={this.state.checked}
     onChange={e => this.handleFieldChange(e)}
   />
 }
 handleFieldChange (e) {
   this.setState({
     checked: e.target.checked
   });
 }
}

export default Checkbox;

Our App class can now use the Checkbox class:

import React, { Component } from 'react';
import Checkbox from './Checkbox';

class App extends Component {
 render () {
   return (
     <form>
       <label>
         Music
         <Checkbox name="music" value="music" checked />
       </label>
       <br />
       <label>
         Dance
         <Checkbox name="dance" value="dance" />
       </label>
     </form>
   );
 }
}

export default App;


Ext JS to React: Form Fields, Checkbox



You can review the sample code on the Git repo.

Toggle

The Ext JS togglefield (Ext.field.Toggle) is a stylized slider field that accepts only two values. The control has a slider element that is moved left to right when clicked / tapped. Using an existing example for reference, we’ll construct our toggle field’s HTML structure using a checkbox and its wrapping label for the form element. We’ll include a span that will operate as our visual control. First, we’ll define the toggle component:

import React, { Component } from 'react';
import './Toggle.css';

class Toggle extends Component {
 state = {
   checked: !!this.props.checked
 }
 render () {
   return (
     <label className="toggle-wrap">
       <div>{this.props.label}</div>
       <input type="checkbox"
         checked={this.state.checked}
         onChange={this.handleToggleChange}
       />
       <div className="toggle-el"></div>
     </label>
   );
 }
 handleToggleChange = (e) => {
   this.setState({
     checked: e.target.checked
   });
 }
}

export default Toggle;

Toggle CSS

With our React component created, we need to add the CSS that styles the toggle field’s UI. In this case, we’ll add it to an {appRoot}/src/Toggle.css file to be imported by the Toggle class.

.toggle-wrap {
  position: relative;
  display: inline-block;
  width: 60px;
  height: 34px;
}
.toggle-wrap input {display:none;}
.toggle-el {
  position: relative;
  cursor: pointer;
  border-radius: 34px;
  height: 100%;
  width: 100%;
  background-color: #ccc;
  -webkit-transition: .4s;
  transition: .4s;
}
.toggle-el:before {
  content: "";
  position: absolute;
  border-radius: 50%;
  height: 26px;
  width: 26px;
  left: 4px;
  bottom: 4px;
  background-color: white;
  -webkit-transition: .25s;
  transition: .25s;
}
input:checked + .toggle-el {
  background-color: #f32195;
  box-shadow: inset 0 -20px 37px 0px rgba(0, 0, 0, 0.36);
}
input:focus + .toggle-el {
  box-shadow: 0 0 1px #f32195;
}
input:checked + .toggle-el:before {
  -webkit-transform: translateX(26px);
  -ms-transform: translateX(26px);
  transform: translateX(26px);
}

Our Toggle field can now be composed in our App:

import React, { Component } from 'react';
import Toggle from './Toggle';

class App extends Component {
 render () {
   return (
     <Toggle />
   );
 }
}

export default App;

This results in a checkbox field (that is hidden, but being toggled via its wrapping <label>) styled as a toggle control.

Ext JS to React: Form Fields, Toggle Field



You can review the sample code on the Git repo.

Wrap Up

In the above field examples we created a loop that populated the field value with either passed-in props or the value manually entered within the field. Often times, the form fields are wrapped by a <form> or some other container that can manage the field values at the container level. Hoisting the value-controlling code above the fields themselves sheds duplicate code, making maintenance of the “dumb” components a bit easier. With the overview of field pieces and parts complete, we’ll focus our attention in the next article on user input moderation using field validations.


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?


>