I'm trying to create a component to handle a list of any object. But the 'handlechange' event doesn't return the selected item on the list. What is the correct approach?
const DropDownList = (props) => {
const [selected, setSelected] = useState(undefined);
const [list, setList] = useState(props.children ? props.children : []);
const handleChange = (e) => {
setSelected(e.target.value);
if (props.setValue) {
props.setValue(e.target.value);
}
};
return (
<div className="col-sm-6">
<div className="form-group">
{props.title ? <label>{props.title}</label> : <></>}
<select className="form-control" value={selected} onChange={handleChange}>
{list.map((item, k) => (
<option key={k} value={item}>{item.label}</option>
))}
</select>
</div>
</div>
)
}
One example of list:
const clima = [
{ label: 'Ensolarado', icon: 'ensolarado' },
{ label: 'Nublado', icon: 'nublado' },
{ label: 'Garoa', icon: 'garoa' },
{ label: 'Chuva Forte', icon: 'chuva_forte' }, ];
const [clima_manha, setClima_Manha] = useState(clima[0])
The use of the component:
<DropDownList value={clima_manha} setValue={setClima_Manha} title="Manhã">{clima}</DropDownList>
CodePudding user response:
Either it is because you use item for value instead of item.label or because you are using setSelected(e.target.value) instead of (setSelected(e)
const DropDownList = (props) => {
const [selected, setSelected] = useState(undefined);
const [list, setList] = useState(props.children ? props.children : []);
const handleChange = (e) => {
setSelected(e.target.value);
if (props.setValue) {
props.setValue(e.target.value);
}
};
return (
<div className="col-sm-6">
<div className="form-group">
{props.title ? <label>{props.title}</label> : <></>}
<select className="form-control" value={selected} onChange={handleChange}>
{list.map((item, k) => (
<option key={k} value={item.label}>{item.label}</option>
))}
</select>
</div>
</div>
)
CodePudding user response:
I solve this setting the selectedIndex to the outside property.
const handleChange = (e) => {
setSelected(e.target.value);
console.log(e)
if (props.setValue) {
props.setValue(list[e.target.selectedIndex]);
}
};
At the list itself, I changed the value to maintain the 'label' of the object.
<select className="form-control" value={selected} onChange={handleChange}>
{list.map((item, k) => (
<option key={k} value={item.label}>{item.label}</option>
))}
</select>
CodePudding user response:
Problem
The value
property in option
element can only be one of the following:
string | number | string[]
Therefore your item
gets called toString
method implicitly and all values in option will have the unexpected string value of '[object Object]'
. This is why your dropdown value is not changing.
Solution
Since your list item is a JSON
, you can do JSON.stringify
each item when setting to value and do JSON.parse
to get back the JSON from the string.
Try like below.
const clima = [
{ label: "Ensolarado", icon: "ensolarado" },
{ label: "Nublado", icon: "nublado" },
{ label: "Garoa", icon: "garoa" },
{ label: "Chuva Forte", icon: "chuva_forte" }
];
const DropDownList = (props) => {
const [selected, setSelected] = React.useState(undefined);
const [list, setList] = React.useState(props.children ? props.children : []);
const handleChange = (e) => {
setSelected(e.target.value);
if (props.setValue) {
props.setValue(JSON.parse(e.target.value));
}
};
return (
<div className="col-sm-6">
<div className="form-group">
{props.title ? <label>{props.title}</label> : <div/>}
<select
className="form-control"
value={selected}
onChange={handleChange}
>
{list.map((item, k) => (
<option key={k} value={JSON.stringify(item)}>
{item.label}
</option>
))}
</select>
</div>
</div>
);
};
function App() {
const [clima_manha, setClima_Manha] = React.useState(clima[0]);
return (
<div className="App">
<DropDownList value={clima_manha} setValue={setClima_Manha} title="Manhã">
{clima}
</DropDownList>
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class='react'></div>
NOTE: You can also use an index of the list item to get it done.