Reputation: 855
I have an issue with react when I want to change the selected option. The problem is that the value is an object and I can't pass it in option value attribut.
See the following code:
class Selector extends React.Component {
contructor(props) {
super(props)
this.state = { obj: null }
this.handleChange = this.handleChange.bind(this)
}
handleChange(e) {
this.setState({obj: e.target.value})
}
render() {
<select onChange={handleChange}>
{this.props.listOption.map((option, index) =>
<option key={index} value={option.obj}>
{option.name}
</option>
)}
</select>
}
}
and with
<Selector option={[{name: "name", obj:{...}}, ...]}>
I need to change the state of the component with the value of the selected option.
What I get when the state change is "object Object"
. I suppose this happens because react can't embed javascript object in attribut of final view. I am right?
Moreover, I set obj
in state as null in the constructor
Is there a right way to do it?
Upvotes: 41
Views: 89273
Reputation: 1282
In my case, I also needed an option object (currentValue
) to be selected at init.
I do not want to search for that object in this.props.listOption
to get its index.
So, instead of replacing the objects with their index, I added a custom attribute data-index
to the options.
The value of attribute data-index
of an option option
can be accessed using option.dataset.index
:
handleChange(e) {
const selectedIndex = e.target.selectedOptions[0].dataset.index];
this.setState({obj: this.props.listOption[selectedIndex].obj})
}
render() {
<select value={currentValue} onChange={handleChange}>
{this.props.listOption.map((option, index) =>
<option key={index} value={option.obj} data-index={index}>
{option.name}
</option>
)}
</select>
}
That code should not be difficult to adapt to multiple selects.
Upvotes: 0
Reputation: 1
Try this following code,
import React from 'react';
class LocationDemo extends React.Component {
constructor(props) {
super(props);
this.state = {
searchLoc: undefined,
selectedLoc: "",
locs:[
{"name" : "Kerala","districts":["Ernakulam", "Trivandrum"]},
{"name" :"Tamil Nadu","districts" :["Palani","Tiruchi"]}
],
};
this.handleChangeLocation = this.handleChangeLocation.bind(this);
}
handleChangeLocation = (event) => {
this.setState({ selectedLoc: event, searchLoc: event.target.value }
, () => console.log("searchLoc", this.state.searchLoc));
}
render() {
return (
<select class="cls-location" id="id-location"
onChange={this.handleChangeLocation}
value={this.state.locs.find(obj => obj.value === this.state.selectedLoc)}
required
>
{
this.state.locs.map(loc => {
return (
<option name={loc.name} value={JSON.stringify(loc)}>{loc.name}</option>
)
})
}
</select>
);
}
}
export default LocationDemo;
Upvotes: 0
Reputation: 3021
Convert the object to JSON string, and pass it as value.
And convert the string back to object in the handler.
handleChange(event) {
let obj = JSON.parse(event.target.value); //object
}
render() {
<select onChange={handleChange}>
{this.props.listOption.map((option, index) =>
<option key={index}
value={JSON.stringify(option)}> //pass object string as value
{option.name}
</option>
)}
</select>
}
Upvotes: 38
Reputation: 10282
You can make use of index
of options
class Selector extends React.Component {
contructor(props) {
super(props);
this.state = { obj: null }
this.handleChange = this.handleChange.bind(this)
}
handleChange(e) {
this.setState({obj: this.props.listOption[e.target.value].obj})
}
render() {
<select onChange={handleChange}>
{this.props.listOption.map((option, index) =>
<option key={index} value={index}>
{option.name}
</option>
)}
</select>
}
}
Moreover, I set obj in state as null in the constructor Is there a right way to do it?
I depends on your requirement. If you want to show at least one option as selected you can keep that instead of null
Upvotes: 64
Reputation: 457
I assume you want only one option will be selected. So the easiest way would be to set selectedIndex. When using construct always think of value type. this.state = { selectedIndex: 0}
Now you've state with selectedIndex object which firstly is equal to 0.
In render method you could then just check for the index:
{this.props.listOption.map((option, index) => {
this.state.selectedIndex == index ? (
<option key={index} value={option.obj} selected>option.name</option>
): (
<option key={index} value={option.obj}>option.name</option>
))}
And on handle change setState with e.target.key.
I may have left syntax errors... Altought I hope it helps.
Upvotes: 3