'React: OnChange for drop down return me the entire <select></select> tag
I am working with react and I have a dropdown menu which is generated like that:
Select a user : <select defaultValue={'DEFAULT'} onChange={this.handleFilter}><option value="DEFAULT" disabled>-- select an gangster --</option>{ddUsers}</select>
ddUsers:
let ddUsers = this.state.users.map(user => <option key={uuid.v4()} value={user}>{user.name}</option>)
And here is my users array:
users : [
{ name: 'All', key : uuid.v4()},
{ name: 'Koko', key : uuid.v4()},
{ name: 'Krikri', key : uuid.v4()},
{ name: 'Kéké', key : uuid.v4()}
]
My problem is that when I want to use the event.target it return me the entire select tag (here the output of console.log(event.target):
<select>
<option value="DEFAULT" disabled selected>-- select an gangster --</option>
<option value="[object Object]">All</option>
<option value="[object Object]">Koko</option>
<option value="[object Object]">Krikri</option>
<option value="[object Object]">Kéké</option>
</select>
where it should normally return me only the user. here is my handleUser (which displays me select tag above):
handleFilter = (event) => {
console.log(event.target);
}
I am lost on what I am missing. I have something similar and it's working perfectly.
Solution 1:[1]
What you want is a key/value at select value, but unfortunately, it does not work. Maybe you'll need to use another component like React-select or use JSON.stringfy() and JSON.parse()
I have made an abstraction code using JSON methods.
const uuid = {
v4() {
return Math.random();
}
};
const users = [
{ name: "All", key: uuid.v4() },
{ name: "Koko", key: uuid.v4() },
{ name: "Krikri", key: uuid.v4() },
{ name: "Kéké", key: uuid.v4() }
];
function App() {
const [selected, setSelected] = React.useState("");
function parseSelected(event) {
const valueToParse = event.target.value;
const itemSelected = JSON.parse(valueToParse);
setSelected(itemSelected);
return;
}
return (
<div>
<select name="any" id="any" onChange={parseSelected}>
{users.map(user => (
<option key={user.key} value={JSON.stringify(user)}>
{user.name}
</option>
))}
</select>
<p>Selected name: {selected.name}</p>
<p>Selected key: {selected.key}</p>
</div>
);
}
the reason is Option HTML interface accepts only DOMString as a value. You can see the docs here
Solution 2:[2]
You could do something like this.. This allows for flexibility so you can use this <select>
component anywhere, using any object with any property.. (using @CarlosQuerioz answer, you'd always have to use an object with a name
key)
Parameter meanings:
- data: array you are wanting to use as options for select
- value: the key from your data property that you want to display
- placeholder: placeholder value (not selectable)
- defaultOption: default selected option (more on this below)
- onSelectChange: event that is fired when selection changes
How we handle defaultOption
:
- If you pass in an array of objects to
defaultOption
we will select the first object in that array, and use the specifiedvalue
key to determine the value to be shown - If you pass in an object, we will show the specified
value
key
To demonstrate the defaultOption
, uncomment each of these values in the example below, you'll see what I mean.
const users = [ // If this was your `data` object
{ name: "Karkar", key: 1 },
{ name: "Koko", key: 2 },
{ name: "Krikri", key: 3 },
{ name: "Kéké", key: 4 }
];
<MySelect
data={users}
value="name" // Must be a valid key that your objects have
onSelectChange={handle}
defaultOption={users[0].name}
//defaultOption={users[1]} // Would display 'Koko' by default
//defaultOption={users} // Would display 'Karkar' by default
/>
EXAMPLE:
const { useState, useEffect } = React;
const { render } = ReactDOM;
function MySelect({ data, value, defaultOption = "", onSelectChange, placeholder = "Select an option" }) {
const [selected, setSelected] = useState(defaultOption);
const handleOnSelectChange = selection => {
onSelectChange && onSelectChange(selection);
}
const handleChange = event => {
let sel = data.find(d => d[value] === event.target.value);
setSelected(sel);
handleOnSelectChange(sel);
};
useEffect(() => {
if (typeof selected === "object") {
let val = selected.length > 0 ? selected[0] : selected;
setSelected(val);
handleOnSelectChange(val);
}
}, []);
return (
<select value={selected[value]} onChange={handleChange}>
<option value="" disabled>
{placeholder}
</option>
{data && data.map((itm, indx) => (
<option key={indx} value={itm[value]}>
{itm[value]}
</option>
))}
</select>
);
}
const users = [
{ name: "Karkar", key: 1 },
{ name: "Koko", key: 2 },
{ name: "Krikri", key: 3 },
{ name: "Kéké", key: 4 }
];
function App() {
const [user, setUser] = useState();
const handle = selectedUser => {
setUser(selectedUser);
};
return (
<div>
<MySelect
data={users}
value="name"
placeholder="Please make a selection"
onSelectChange={handle}
//defaultOption={users[0].name}
//defaultOption={users[0]}
defaultOption={users}
/>
{user && <pre>{JSON.stringify(user, null, 2)}</pre>}
</div>
);
}
render(<App />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.9.0/umd/react-dom.production.min.js"></script>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 |