Search code examples
angularjsreactjsequivalent

Angular 1.X ng-options equivalent using React


Angular 1.X has ng-options for the choices in a select dropdown, each item being an object. In plain HTML, the value of an option can only be a string. When you select one option in Angular, you can see the actual selected object while in plain html, you can only get that string value.

How do you do the equivalent of that in React (+Redux)?


Solution

  • I came up with a solution that does not use JSON.stringify / parse for the value of the select React element nor does it use the index of the array of choice objects as the value.

    The example is a simple select dropdown for a person's gender -- either male or female. Each of those choices is an actual object with id, text, and value properties. Here is the code:

    MySelect component

    import React, { Component } from 'react';
    
    class MySelect extends Component {
      onGenderChange = (event) => {
        // Add the second argument -- the data -- and pass it along
        // to parent component's onChange function
        const data = { options: this.props.options };
        this.props.onGenderChange(event, data);
      }
    
      render() {
        const { options, selectedOption } = this.props;
    
        // Goes through the array of option objects and create an <option> element for each
        const selectOptions = options.map(
          option => <option key={option.id} value={option.value}>{option.text}</option>
        );
    
        // Note that if the selectedOption is not given (i.e. is null),
        // we assign a default value being the first option provided
        return (
          <select
            value={(selectedOption && selectedOption.value) || options[0].value}
            onChange={this.onGenderChange}
          >
            {selectOptions}
          </select>
        );
      }
    }
    

    App component that uses MySelect

    import _ from 'lodash';
    import React, { Component } from 'react';
    
    class App extends Component {
      state = {
        selected: null
      }
    
      onGenderChange = (event, data) => {
        // The value of the selected option
        console.log(event.target.value);
        // The object for the selected option
        const selectedOption = _.find(data.options, { value: parseInt(event.target.value, 10) });
        console.log(selectedOption);
    
        this.setState({
          selected: selectedOption
        });
      }
    
      render() {
        const options = [
          {
            id: 1,
            text: 'male',
            value: 123456
          },
          {
            id: 2,
            text: 'female',
            value: 654321
          }
        ];
    
        return (
          <div>
            <label>Select a Gender:</label>
            <MySelect
              options={options}
              selectedOption={this.state.selected}
              onGenderChange={this.onGenderChange}
            />
          </div>
        );
      }
    }
    

    Lodash is used to look up the choice object in the array of choice objects inside the onGenderChange function in the App component. Note that the onChange passed to the MySelect component requires two arguments -- an extra data argument is added in order to be able to access the choice objects ("options"). With that, you can just set the state (or call an action creator if using Redux) with the choice object for the selected option.