John Younan John Younan - 3 months ago 147
React JSX Question

Can't get the target attributes of material-ui select react component

I'm trying to get the id,name, and value from Select field element of Material-UI react component.

This is my container:

//some code is removed to keep things simple
class MyContainer extends Component {

constructor(props) {
super(props);
}

render() {
return(
<MyComp onChange={this._onChange.bind(this)} />
);
}

_onChange(evt) {
console.log(evt.target);
console.log(evt.target.id); //blank
console.log(evt.target.name); //undefined
console.log(evt.target.value); //html value of selected option!

}

}
export default connect(select)(MyContainer);


in my presentational component:

import React, {Component} from 'react';
import Select from 'material-ui/SelectField';
import MenuItem from 'material-ui/MenuItem';

const someData = ["aaaa", "bbbb", "ccccc"];

class MyComp extends Component {

render() {
const {onChange} = this.props;

return (
<form >
<Select
value={this.props.test}
name={"test"}
id={"test"}
onChange={this.props.onChange}
hintText={"Select a fitch rating service"}>
{
someData.map((e) => {
return <MenuItem key={Math.random()} value={e} primaryText={e}/>
})
}
</Select>
</form>
);
}
}


Problem is that
_onChange(evt)
is giving this values:

evt.id is blank
evt.name is undefined
evt.target.value is <div>whatever the selected value was</div>


It seems as though the passed argument to
_onChange(evt)
is not the
SELECT
but rather the option since when i print out
evt.target
it gives
<div>whatever the selected value was</div>
. anyone knows why? If i use a plain select field (not material-ui) then this works as expected (i.e. i can get the id,name, correct value of selected option). How do i get the target id, name..etc from onChange event of Material-UI Select component?

P.S i'm using the same
_onChange
method for TextField component of material-ui and it works there. I've also tried:

_onChange = (event, index, value) => {
console.log(event.target.id); //blank
console.log(event.target.name); //undefined
console.log(index); //correct index
console.log(value); //correct value
};

Answer

Update 2

In response to your comments:

As per the material-ui docs, getting back the touchtap event on option element rather than the select element is expected. If you want the id and name of the element, I would suggest binding the variables to the callback:

The onchange method in the parent component:

_onChange(id, name, evt, key, payload) {

  console.log(id);  //id of select
  console.log(name); //name of name
  console.log(payload); //value of selected option
}

And when you attach it to the select component, you need to use bind

   <Select
     value={this.props.test}
     name={"test"}
     id={"test"}
     onChange={this.props.onChange.bind(null,"id","name")}
     hintText={"Select a fitch rating service"}>

Update

Here are the react event docs. Under the event-pooling you will find reference to the use of e.persists() in the block quote. The explanation given in this issue is that React pools the event object, so it get's reused when another event is fired.


React has a rather special event object. It wraps the native event in a synthetic event, which is what event points to in your _onChange method. The problem is that this synthetic event object is recycled and reused for the next event, so it is garbage collected and set to null. I don't think this is well documented, but I'll search for a link and update this answer once I find it.

The solution is for the first line in your event handler to make a copy of the event, persist it, or get a reference to the native event:

Make a copy of the event

_onChange = (event, index, value) => {
  e = _.cloneDeep(event); // Here I'm using the cloneDeep method provided by underscore / lodash . User whatever library you prefer. 
  console.log(e.target.id); 
  console.log(e.target.name); 
};

Persist the event

_onChange = (event, index, value) => {
  event.persist() // This stops react from garbage collecting the event object. It may impact performance, but I doubt by much.
  console.log(event.target.id); 
  console.log(event.target.name); 
};

Get a reference to the native event object

_onChange = (event, index, value) => {
  e = event.native; // This looks the same as a vanilla JS event
  console.log(e.target.id); 
  console.log(e.target.name); 
};