React-select: Get name of select component onChange

Created on 15 Oct 2015  路  20Comments  路  Source: JedWatson/react-select

Is it possible to detect what select component triggered an onChange event? Doesn't look like it in the docs, but maybe there is a workaround?

Use case: I have several select components that are filtering a table, right now every select component needs its own handleChange function triggered by OnChange, but all I need is the name to use as a key to make my updates.

e.g. would be nice to do something like:

constructor() {
  this.state = {
    branchFilter: '',
    moduleFilter: ''
  }
}

handleFilterChange(newValue, [selectedOptions], name) {
   this.setState({ 
       [name]: newVal
   });
}

render() {
   return (
      <div className='branch-filter'>
        <Select
          name="branchFilter"
          value={this.state.branchFilter}
          options={uniqueBranches(this.props.branches)}
          onChange={this.handleBranchFilterChange}
        />
        <Select
          name="moduleFilter"
          value={this.state.moduleFilter}
          options={uniqueModules(this.props.branches)}
          onChange={this.handleModuleFilterChange}
        />
      </div>

Most helpful comment

The following code works for me

class MyComponent extends React.Component {

  onSelectChange(name, value) {
    let obj = {};
    obj[name] = value;
    this.setState(obj);
  }

  render() {
    return (
        <Select name="myName" onChange={this.onSelectChange.bind(this, 'myName')}/>
    );
  }

}

and this one for a .map() iterator

const Selects = [
  {
    name: 'firstSelect',
    options: [
      {value: 'one', label: '1'},
      {value: 'two', label: '2'},
    ],
  },
  {
    name: 'secondSelect',
    options: [
      {value: 'one', label: '1'},
      {value: 'two', label: '2'},
      {value: 'three', label: '3'},
    ],
  },
];

class MyC extends React.Component {

  onSelectChange(name, value) {
    let obj = {};
    obj[name] = value;
    this.setState(obj);
  }

  render() {
    return (
      <div>
        {Selects.map((select, i)=>{
          return (
            <Select
              key={i}
              name={select.name}
              options={select.options}
              onChange={this.onSelectChange.bind(this, select.name)}
            />
          );
        })}
      </div>
  }

}

All 20 comments

+1. I just came across the same issue. I am using <Select> within a map.

The workaround I use is to return a function for each item in the collection.

Component = React.createClass({

  handleSelectChange: function(name) {
    return function(newValue) {
        // perform change on this.state for name and newValue
    }.bind(this);
  },

  render: function() {
   return (
      <div>
        <Select ...attrs...  onChange={this.handleSelectChange('first')} />
        <Select ...attrs...  onChange={this.handleSelectChange('second')} />
      </div>);
  }
});

+1

I have a similar issue. I'm using this component in an Angular app, and the select is inside an ng-repeat. In the onChange callback, I need some way to know which select triggered the callback, otherwise I can't update that specific select with a new value. I'm adding a unique ID to the name attribute, so passing that at the very least as another parameter in the onChange callback would be helpful.

I changed the code in react-select.js to the following and was able to get what I needed. Notice how the last line passes this.props.name as a second argument.

    setValue: function setValue(value) {
        var _this = this;

        if (!this.props.onChange) return;
        if (this.props.simpleValue && value) {
            value = this.props.multi ? value.map(function (i) {
                return i[_this.props.valueKey];
            }).join(this.props.delimiter) : value[this.props.valueKey];
        }
        this.props.onChange(value, this.props.name);
    },

+1 for this.

this component is awesome but imho should feature a similar API as literally just about every other javascript event emitter/handler, in which event emitters emit event objects and event handlers expect an event object as the first -- if not, only -- argument.

+1, this is a very non standard way of raising onChange.

+1 pleasssseeeeee :(

The following code works for me

class MyComponent extends React.Component {

  onSelectChange(name, value) {
    let obj = {};
    obj[name] = value;
    this.setState(obj);
  }

  render() {
    return (
        <Select name="myName" onChange={this.onSelectChange.bind(this, 'myName')}/>
    );
  }

}

and this one for a .map() iterator

const Selects = [
  {
    name: 'firstSelect',
    options: [
      {value: 'one', label: '1'},
      {value: 'two', label: '2'},
    ],
  },
  {
    name: 'secondSelect',
    options: [
      {value: 'one', label: '1'},
      {value: 'two', label: '2'},
      {value: 'three', label: '3'},
    ],
  },
];

class MyC extends React.Component {

  onSelectChange(name, value) {
    let obj = {};
    obj[name] = value;
    this.setState(obj);
  }

  render() {
    return (
      <div>
        {Selects.map((select, i)=>{
          return (
            <Select
              key={i}
              name={select.name}
              options={select.options}
              onChange={this.onSelectChange.bind(this, select.name)}
            />
          );
        })}
      </div>
  }

}

If anyone wants to get the DOM node (or event.target) whose value was changed, they can patch Select.js and pass this.getDOMNode() or this.wrapper as 2nd argument to the 'onChange' handler, like so:

    setValue (value) {
        if (this.props.autoBlur){
            this.blurInput();
        }
        if (!this.props.onChange) return;
        if (this.props.required) {
            const required = this.handleRequired(value, this.props.multi);
            this.setState({ required });
        }
        if (this.props.simpleValue && value) {
            value = this.props.multi ? value.map(i => i[this.props.valueKey]).join(this.props.delimiter) : value[this.props.valueKey];
        }
        this.props.onChange(value, this.getDOMNode()); // <--------- PATCH (or use this.wrapper)
    },

The first thing that a user will encounter most often is stuck on this issue!

This might not be relevant to the question, but I thought it might help someone. Note the onChange prop. This is another way to pass multiple parameters to the onChange function.

id="state-select"
options={options}
clearable={true}
name="select-name"
placeholder={'Search'}
value={this.props.selectValue}
onChange={(newValue, extra) => this.props.handleSelectChange(newValue, 'extra parameter')}
/>

This library is just not worth using.. You cant dynamicaly use one function for multiple selects, you cant normally style your options.. Why would you even create that lib if you cant customize it at al..

For uniformity's sake, I needed to access data- attributes and e.target.value just like I do for every other type of input in React. So, I just made a wrapper to do this. Mind you, I'm using v1.x, but this should still work:

import React from 'react';
import ReactSelect from 'react-select';

export class Select extends React.PureComponent {
  handleChange = (e) => {
    const { props } = this;
    if (!props.onChange) {
      return;
    }
    // Create a fake target with fake attributes based on data- props...
    const attributes = {};
    for (let key in props) {
      if (key.startsWith('data-')) {
        attributes[key] = {
          value: props[key],
        };
      }
    }
    props.onChange({
      target: {
        attributes,
        value: e.value,
      },
      ...e,
    });
  };

  render() {
    return (
      <ReactSelect
        {...this.props}
        onChange={this.handleChange}
      />
    );
  }
}

https://react-select.com/upgrade-guide
Seems like there is now a second argument actionMeta for onChange. name is accessible from there.

Hi everyone, I do it like this:

handleSelectChange = name => selectedOption => this.setState({[name] : selectedOption})

<Select ...attrs... onChange={this.handleSelectChange("foo")} />

It looks cleaner for me :D

ps: I just started using react a few hours ago, please let me know if I shouldn't do it that way

@rizkyarlin thank you so much for sharing your solution. It worked perfectly for me.

@markoj3s is correct also. The name prop is passed to the action argument for the onChange event handler.

import React from 'react';
import ReactSelect from 'react-select';

export class Select extends React.PureComponent {
  handleChange = (value, action) => {
    console.log(action.name) //exampleSelectName
  };

  render() {
    return (
      <ReactSelect
        name='exampleSelectName'
        onChange={this.handleChange}
      />
    );
  }
}

Can we close this now that the second parameter can be used to get the name?

The following code works for me

class MyComponent extends React.Component {

  onSelectChange(name, value) {
    let obj = {};
    obj[name] = value;
    this.setState(obj);
  }

  render() {
    return (
        <Select name="myName" onChange={this.onSelectChange.bind(this, 'myName')}/>
    );
  }

}

and this one for a .map() iterator

const Selects = [
  {
    name: 'firstSelect',
    options: [
      {value: 'one', label: '1'},
      {value: 'two', label: '2'},
    ],
  },
  {
    name: 'secondSelect',
    options: [
      {value: 'one', label: '1'},
      {value: 'two', label: '2'},
      {value: 'three', label: '3'},
    ],
  },
];

class MyC extends React.Component {

  onSelectChange(name, value) {
    let obj = {};
    obj[name] = value;
    this.setState(obj);
  }

  render() {
    return (
      <div>
        {Selects.map((select, i)=>{
          return (
            <Select
              key={i}
              name={select.name}
              options={select.options}
              onChange={this.onSelectChange.bind(this, select.name)}
            />
          );
        })}
      </div>
  }

}

This works for me. Thanks bro

I modified my option as _{ value: valuetext, label: labeltext, name: desiredNameForThisOption_}.

And select is used like this:
_