I need to make that when selecting checkbox Select All, the rest of the checkboxes from the list are checked, and each checkbox can be selected separately. But when select one of the checkboxes does not checked the previous checkbox.
sandbox
const options = [ 'Selected Item 1', 'Selected Item 2', 'Selected Item 3'];
export default function App() {
const [selected, setSelected] = useState([]);
const isAllSelected =
options.length > 0 && selected.length === options.length;
const handleChange = (event) => {
const value = event.target.value;
console.log(value)
if (value === "all") {
setSelected(selected.length === options.length ? [] : options);
return;
}
setSelected(value);
};
const listItem = options.map((option) => {
return (
<div key={option}>
<Checkbox
value={option}
onChange={handleChange}
checked={selected.includes(option) } />
<span>{option}</span>
</div>
)
})
return (
<div style={{ display: 'flex', alignItems: 'center', margin: 10 }}>
<Checkbox
value='all'
onChange={handleChange}
checked={isAllSelected}
/>
<span> Select All</span>
{listItem}
</div>
);
}
I need to make that when selecting checkbox Select All, the rest of the checkboxes from the list are checked, and each checkbox can be selected separately. But when select one of the checkboxes does not checked the previous checkbox.
sandbox
const options = [ 'Selected Item 1', 'Selected Item 2', 'Selected Item 3'];
export default function App() {
const [selected, setSelected] = useState([]);
const isAllSelected =
options.length > 0 && selected.length === options.length;
const handleChange = (event) => {
const value = event.target.value;
console.log(value)
if (value === "all") {
setSelected(selected.length === options.length ? [] : options);
return;
}
setSelected(value);
};
const listItem = options.map((option) => {
return (
<div key={option}>
<Checkbox
value={option}
onChange={handleChange}
checked={selected.includes(option) } />
<span>{option}</span>
</div>
)
})
return (
<div style={{ display: 'flex', alignItems: 'center', margin: 10 }}>
<Checkbox
value='all'
onChange={handleChange}
checked={isAllSelected}
/>
<span> Select All</span>
{listItem}
</div>
);
}
Share
asked Jul 5, 2021 at 5:09
stepbystepstepbystep
3913 gold badges8 silver badges23 bronze badges
3
- you want to implement multi checkbox selection right? – Rahul Kumar Commented Jul 5, 2021 at 5:15
- @RahulKumar yes absolutly – stepbystep Commented Jul 5, 2021 at 5:17
- added the answer below – Rahul Kumar Commented Jul 5, 2021 at 6:26
4 Answers
Reset to default 0When you click on checkboxes other than "all" checkbox, you are just setting your selected
state to that value: setSelected(value);
. There are 2 problems with this code - 1) In your case the selected
state should always be an array, but you are changing that to a string. 2) you are disregarding any previous values that might be added to the selected
state. You must figure out if the clicked checkbox was already in the selected
state or not. if not, you should add it to the state. If it was then you should remove it from the state. Here is how you can do this:
const handleChange = (event) => {
const value = event.target.value;
console.log(value)
if (value === 'all') {
setSelected(selected.length === options.length ? [] : options);
return;
}
if (selected.indexOf(value) !== -1) { // if value already present
const newSelected = selected.filter((s) => s !== value );
setSelected(newSelected);
} else { // if value not present
setSelected([ ...selected, value ]);
}
}
You can make a data-structure like [{data:any, selected: boolean}, {data:any, selected: boolean}]
Then you loop through it and display them as
const [items, setItems] = useState<Asset[]>([]);
const [select, setSelect] = useState(false)
const handleChange = (index, checked) => {
if(select && !checked) setSelect(false)
const itemRef = [...items];
itemRef[index].selected = checked
setItems([...itemRef]);
}
const handleChangeAll = (checked) => {
const itemRef = [...items];
itemRef.forEach((_item, i) => {
itemRef[i].selected = checked
})
setSelect(checked)
setItems([...itemRef]);
}
------
All selection checkbox
<Checkbox
checked={select}
onChange={(_e, checked) => handleChangeAll(checked)}
/>
** items **
items.map((item, i) => (
<Checkbox
key={item.data.id}
checked={item.selected}
onChange={(_e, checked) => handleChange(index, checked)}
/>
))
Once it is done if you want to extract the selected data, you can just apply the filter method based on item.selected
from items
array,
Need to update selected
options array instead of assigning the value directly inside handleChange
method. So first check if selected list contains the checked option
if it contains then remove
it, otherwise add
it to the selected list.
const handleChange = (event) => {
const value = event.target.value;
console.log(value);
if (value === "all") {
setSelected(selected.length === options.length ? [] : options);
return;
}
// added below code to update selected options
const list = [...selected];
const index = list.indexOf(value);
index === -1 ? list.push(value) : list.splice(index, 1);
setSelected(list);
};
Sandbox link here
Your logic for selecting all the checkboxes works quite well. As for the problem of selecting a checkbox separately you can fix this with the following code.
First we check if the value
is already in the selected
array, if not we can simply return a new array with the prevSelected
and the new one. If the value
already exists in the prevSelected
we can remove it using the filter
method.
const handleChange = (event) => {
const value = event.target.value;
if (value === "all") {
setSelected(selected.length === options.length ? [] : options);
return;
}
setSelected((prevSelected) => {
if (!prevSelected.includes(value)) return [...prevSelected, value];
return prevSelected.filter((option) => option !== value);
});
};
Little side note, it's not remended to create your listItem
array as a variable inside your ponent. As this creates a new array of checkboxes everytime your states change. You could simply map over them in your return
statement.
return (
<div style={{ display: "flex", alignItems: "center", margin: 10 }}>
<Checkbox value="all" onChange={handleChange} checked={isAllSelected} />
<span> Select All</span>
{options.map((option) => {
return (
<div key={option}>
<Checkbox value={option} onChange={handleChange} checked={selected.includes(option)} />
<span>{option}</span>
</div>
);
})}
</div>
);