Reputation: 10240
I have several sets of checkboxes that should work independently and a toggle that toggles them all (within their groups only). I have two states (one for the toggle and one for the checkboxes). I can identify the checkbox I'm clicking with the event.target.value, that way I can manipulate it individually. But I'm having trouble controlling them all at once with the toggle as well as making the toggle come active when someone independently checks them all true.
In summary
1- when the toggle is on, all checkboxes within its group come on, same for off
2- When I turn on each checkbox individually until they are all on, the toggle turns on and when I uncheck one of them, the toggle turns off
I've made a sandbox for you to play on. Thanks in advance
const [active, setActive] = useState(false)
const [singleactive, setSingleActive] = useState([])
const handleSwitch = (e) => {
if(e.target.value === "Select All") {
setActive(e.target.checked)
setSingleActive([...singleactive])
} else {
setSingleActive([])
}
}
const handleSingleSwitch = (e) => {
const index = singleactive.indexOf(e.target.value)
if(index === -1) {
setSingleActive([...singleactive, e.target.value])
} else {
setSingleActive(singleactive.filter((singleactive) => singleactive !== e.target.value))
}
}
Upvotes: 1
Views: 456
Reputation: 10240
Well, I figure it out. Though I find answering your own question a bit pretentious lol, here it is in case it helps
Updated states and functions
const [active, setActive] = useState(false)
/// fill a new array with false values for the length of the data to load them all unchecked
const [checkedState, setCheckedState] = useState(new Array(data.length).fill(false));
const handleSwitch = (e) => {
if(e.target.checked) {
/// if the toggle event comes back checked, set the active state to true and re-fill the array with all true values which is what Select All does
setActive(true)
setCheckedState(new Array(data.length).fill(true));
} else {
/// if the toggle event comes back unchecked, set the active state to false and re-fill the array with all false values which is what Deselect All does
setActive(false)
setCheckedState(new Array(data.length).fill(false));
}
}
const handleOnChange = (position) => {
// every time you click an infividual checkbox, map through the state and compare its index with the position in the array. If it's true, make it true otherwise false; then set the state with this value
const updatedCheckedState = checkedState.map((item, index) => {
return (
index === position ? !item : item
)}
);
setCheckedState(updatedCheckedState);
/// if the new generated array of values contains at least one false in it, set the active class on the toggle to false, but if there isn't at least one false, then all are true, so set the active class to true on the toggle
if(updatedCheckedState.includes(false)) {
setActive(false)
} else {
setActive(true)
}
};
I also removed the value on the toggleAll checkbox that I inadvertently set statically to Select All. This way I can control it via state
<Stack direction="row" spacing={1} alignItems="center">
<Typography>Deselect All</Typography>
<Switch
size="small"
checked={active}
onChange={handleSwitch} />
<Typography>Select All</Typography>
</Stack>
And lastly the checkboxes
<FormControlLabel
control={
<Checkbox
size="small"
name={item.toLowerCase()}
value={item.toLowerCase()}
checked={checkedState[index]}
onChange={() => handleOnChange(index)}
/>
}
label= {item.replaceAll('_', ' ')} />
Check the sandbox for the updated code.
Upvotes: 1