I have a problem where I have to render 4 dropdowns, each with similar options(i just rendered 1 here). If I select an option in any one of the dropdowns, that option should not be available in the other three.
How should I update the selected_planets in the state? The below code updates the selected_planets from 1 select dropdown. But still that same option is available everywhere and I could not able to get 4 different options inside selected_planets array? How should I proceed?
Also, the response from API fetch is an array of objects, which I mapped through and update in planets Array. For demo purpose, let's consider, planets: [Neptune, Saturn, Mars, Earth, Venus, Jupiter]
import React, { Component } from 'react';
export default class Dashboard extends Component {
state = {
planets: [],
selected_planets: []
};
componentDidMount() {
fetch('url')
.then(response => {
return response.json();
})
.then(data => {
this.setState({ planets: data });
});
}
handleSelect = event => {
this.setState({ selected_planets: [event.target.value] });
};
render() {
let select_Planets = this.state.planets.map(planet => {
return planet.name;
});
let options = select_Planets.map(planet => (
<option key={planet} value={planet}>
{planet}
</option>
));
return (
<select onChange={this.handleSelect}>
<option defaultChecked></option>
{options}
</select>
);
}
}
The first and foremost thing we need to do is change the select element and make it let use select multiple values. The second thing we need to change is the constructor method and add an array so that we can use that array to store multiple selections from the user.
To update our state, we use this. setState() and pass in an object. This object will get merged with the current state. When the state has been updated, our component re-renders automatically.
This can be achieved by producing a new set of options for each dropdown on render based off of what are the currently selected options, and what is the selected option for that dropdown.
First make sure each dropdown is binding to a property in your component's state and updating on change:
constructor() {
super();
this.state = {
planets: ["a", "b", "c", "d"],
inputs: {
d1: "",
d2: ""
}
};
this.handleChange = this.handleChange.bind(this);
}
handleChange({ target }) {
this.setState({
...this.state,
inputs: {
...this.state.inputs,
[target.name]: target.value
}
});
}
<select
name="d1"
value={this.state.inputs.d1}
onChange={this.handleChange}>
Then you can obtain a list of the selected planets within the render
method by converting the input object into an array using Object.values()
:
const selectedPlanets = Object.values(this.state.inputs);
Then create a new array for each of the dropdowns which will omit any planets which have already been selected unless it is selected by that particular dropdown itself:
const d1Options = this.state.planets.filter(
p => !selectedPlanets.find(sP => sP === p) || p === this.state.inputs.d1
);
const d2Options = this.state.planets.filter(
p => !selectedPlanets.find(sP => sP === p) || p === this.state.inputs.d2
);
<select
name="d1"
value={this.state.inputs.d1}
onChange={this.handleChange}>
<option></option>
{d1Options.map(o => (
<option key={o}>{o}</option>
))}
</select>
I've put together a working example here:
https://codepen.io/curtis__/pen/pozmOmx
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With