I have an array of objects and I am trying to group the objects by type, like this:
const el = {
Type1: [
{
param1: 1,
param2: value1,
position: 1,
type: 'Type1'
}, {
param1: 2,
param2: value2,
position: 2,
type: 'Type1'
}
],
Type2: [
{
param1: 3,
param2: value3,
position: 1,
type: 'Type2'
}, {
param1: 4,
param2: value4,
position: 2,
type: 'Type2'
}, {
param1: 5,
param2: value5,
position: 3,
type: 'Type2'
}
]
}
The objects in Type property represent choices for radio buttons. This way I set the first choice checked by default:
const groupBy = (array, key) => {
return array.filter(o => o.checked != undefined).reduce((result, currentValue) => {
(result[currentValue[key]] = result[currentValue[key]] || []).push(
currentValue);
return result;
}, {});
};
const [state, setState] = useState({
buttonsTypes: groupBy([...arrayObjects, arrayObjects.map((item, index) => item.position === 1 ? item['checked'] = true : item['checked'] = false)], 'type'),
selections: arrayObjects.filter(item => item.checked)
});
My question is how to map this dynamically and change the checked value on click? I tried this so far:
const selectChoice = (obj) => {
setState(prevState => {
return {
buttonsTypes: ... // Not sure how to update the checked value only for the selection of the specific obj.Type
selections: ...
};
});
};
{Object.entries(state.buttonsTypes).map((item, index) => {
return <React.Fragment>
<div className="some-class"/>
<span id="text">{item[0]}</span>
<div id="radio-button-wrapper">
{item[1].map((choice, index) => {
return <label className="label-css">
<input type="radio" name={choice.param2} value={choice.param1} checked={choice.checked} onClick={() => selectChoice(choice)}/>
</label>
})
}
</div>
</React.Fragment>
})
}
Can anyone suggest some examples or another approach on how to solve this?
Update: As suggested in the answer, I solved it this way by keeping only an array of the selected choices for each radio group:
const selectChoice = (obj) => {
setState(prevState => {
const sel = prevState.selections;
const idx = sel.findIndex(item => item.type === obj.type);
if (idx === -1) {
sel.push(obj);
} else {
sel[idx] = obj;
}
return {
...prevState,
selections: sel
};
});
};
Inside the mapping:
{Object.entries(state.groupedArray).map((item, index) => {
return <React.Fragment>
<div className="some-class"/>
<span id="text">{item[0]}</span>
<div id="radio-button-wrapper">
{item[1].map((choice, index) => {
return <label className="label-css">
<input type="radio" name={choice.param2} value={choice.param1} defaultChecked={choice.position === 1} onClick={() => selectChoice(choice)}/>
</label>
})
}
</div>
</React.Fragment>
})
}
Would appreciate if anyone has any suggestions or comments for improvements.
Why not use 'state' to keep track of the index of the checked radio button?
Then inside of {item[1].map((choice, index) => {...}}
you can check whether the currently saved 'state' matches the current index in the input you're trying to return
and update the index of the currently checked radio input by attaching your selectChoice handler
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