Reputation: 35
I'm working on a form which contains a section where users can choose the quantity and category of a concert ticket in a dropdown. This component is dynamically created and it can have more items(quantity + category). The dropdowns of the categories are related to each other. So if you choose one category the value of the other dropdowns should be set to the same selected value. But I also need the name of each category dropdown for validation.
This is how I created the category object:
const createCategory = () => {
let cat = {}
let nestedCat = {}
for (let it in item) {
for (let bt in item[it].buyertypes) {
cat2[item[it].buyertypes[bt].id] = ''
}
cat[item[it].id] = nestedCat
nestedCat = {}
}
return cat
}
const [category, setCategory] = useState(createCategory());
This is the initial object:
{
9871: { 1: "", 2: "", 3: "" }
9872: { 5: "", 6: "", 8: "" }
}
How I show and handle the ticket component
const handleQuantity = e => {
setQuantity({
...quantity,
[e.target.name]: e.target.value
});
}
const handleCategory = e => {
setCategory({
...category,
[e.target.name]: e.target.value
});
}
const ShowData = () => {
let ticketIem = []
for (let it in item) {
for (let bt in item[it].buyertypes) {
let buyerType = item[it].buyertypes[bt]
ticketIem.push({
'price': buyerType.prices, 'catId': item[it].id,
'qntId': item[it].buyertypes[bt].id
})
}
}
return (
<div>
{ticketIem.map((i, index) => (
<div key={index} >
<div>
<label>Number</label>
<select
value={quantity[i.qntId]}
onChange={handleQuantity}
name={i.qntId}
>
<option value={0}>0</option>
<option value={1}>1</option>
</select>
</div>
<div>
<label>Category</label>
<select
value={category[i.catId]}
onChange={handleCategory}
name={i.catId}
>
<option value="">Choose</option>
{categories.map((cat, index) => (
<option key={index} value={cat.id} name={i.qntId}>
{cat.description} {cat.value}
</option>
))}
</select>
</div>
</div>
))}
</div>
)
}
After selecting an option in the dropdown the category object will be set like:
{
9871: "11", 9872: "7"
}
but I expect:
{
9871: { 1: "11", 2: "11", 3: "11" }
9872: { 5: "7", 6: "7", 8: "7" }
}
Upvotes: 1
Views: 1482
Reputation: 203427
If you want to set all the nested properties of a specific category or quantity then you'll need to also iterate the keys of those nested properties. Use Object.keys
to get an array of the nested object's keys, and reduce them into a new object with the new value set for each key.
I suggest also using a functional state update since each update depends on the existing/current state as it is shallowly copied into the next state.
const handleQuantity = (e) => {
setQuantity((quantity) => ({
...quantity,
[e.target.name]: Object.keys(quantity[e.target.name]).reduce(
(obj, key) => ({
...obj,
[key]: e.target.value
}),
{}
)
}));
};
const handleCategory = (e) => {
setCategory((category) => ({
...category,
[e.target.name]: Object.keys(category[e.target.name]).reduce(
(obj, key) => ({
...obj,
[key]: e.target.value
}),
{}
)
}));
};
Upvotes: 1