英文:
How can I check all child items when the main head is checked and vice-versa?
问题
我正在制作一个下拉列表,在这个列表中,如果选择了主头部,我想要选择所有子项目,如果所有子项目都被选择了,那就选择头部。
这是我的列表组件。
我知道逻辑,但我无法实现它。我不知道该怎么做。我知道通过检查所有子项目是否被选中,我们可以选择头部,但我不知道如何实现这一部分。
英文:
I am making a dropdown list in which I want to select all the sub-items if the main head is checked, and select the head, if all the sub-items are checked.
const DropDownList = ({ data }) => {
const [open, setOpen] = useState({});
const [checked, setChecked] = useState({});
const handleClick = (department) => {
setOpen((prevOpen) => ({
...prevOpen,
[department]: !prevOpen[department],
}));
};
const handleCheck = (item) => {
setChecked((prevChecked) => ({
...prevChecked,
[item]: !prevChecked[item],
}));
};
return (
<List>
{data.map((department) => (
<React.Fragment key={department.department}>
<ListItem
sx={{ cursor: "pointer" }}
onClick={() => handleClick(department.department)}
>
<Checkbox
checked={checked[department.department] || false}
onChange={() => handleCheck(department.department)}
/>
<ListItemText primary={department.department} />
{open[department.department] ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open[department.department]} unmountOnExit>
<List
component="div"
sx={{ padding: "0 35px", cursor: "pointer" }}
disablePadding
>
{department.sub_departments.map((subDepartment) => (
<ListItem key={subDepartment}>
<Checkbox
checked={checked[subDepartment] || false}
onChange={() => handleCheck(subDepartment)}
/>
<ListItemText primary={subDepartment} />
</ListItem>
))}
</List>
</Collapse>
</React.Fragment>
))}
</List>
);
};
export default DropDownList;
This is my List component.
I know the logic, but I can't implement it. I don't know how to. I know that by checking if all sub-items are checked, we can check the head too, but I don't know how to implement this bit.
答案1
得分: 0
对于"如果选中主头部,则选择所有子项",考虑修改handleCheck()
以传递一个item
对象。这将让我们知道所选项目的sub_departments
:
const handleCheck = (item) => {
setChecked((prevChecked) => ({
...prevChecked,
[item.department]: !prevChecked[item.department],
}));
};
…
<Checkbox
…
onChange={() => handleCheck(department)}
/>
…
<Checkbox
…
onChange={() => handleCheck({ department: subDepartment })}
/>
如果它被选中,请检查其sub_departments
:
const handleCheck = (item, parent = {}) => {
setChecked((prevChecked) => {
const list = {
...prevChecked,
[item.department]: !prevChecked[item.department],
};
if (list[item.department]) {
if (item.sub_departments) {
item.sub_departments.forEach(sub => {
list[sub] = true;
});
}
}
return list;
});
};
对于"如果所有子项都被选中,请选择头部",将父部门项目作为handleCheck()
的第二个参数传入:
const handleCheck = (item, parent = {}) => {
…
}
…
<Checkbox
…
onChange={() => handleCheck({ department: subDepartment }, department)}
/>
然后,如果所有sub_departments
都被选中,请检查父部门:
const handleCheck = (item, parent = {}) => {
setChecked((prevChecked) => {
const list = {
...prevChecked,
[item.department]: !prevChecked[item.department],
};
if (list[item.department]) {
…
if (parent.sub_departments && parent.sub_departments.length) {
let checkParent = true;
for (const subItem of parent.sub_departments) {
if (!list[subItem]) {
checkParent = false;
break;
}
}
if (checkParent) {
list[parent.department] = true;
}
}
}
return list;
});
};
完整示例:
const { useState } = React;
const { List, ListItem, Checkbox, ListItemText, Collapse } = MaterialUI;
const ExpandMore = () => 'ExpandMore';
const ExpandLess = () => 'ExpandLess';
const DropDownList = ({ data }) => {
const [open, setOpen] = useState({});
const [checked, setChecked] = useState({});
const handleClick = (department) => {
setOpen((prevOpen) => ({
...prevOpen,
[department]: !prevOpen[department],
}));
};
const handleCheck = (item, parent = {}) => {
setChecked((prevChecked) => {
const list = {
...prevChecked,
[item.department]: !prevChecked[item.department],
};
if (list[item.department]) {
if (item.sub_departments) {
item.sub_departments.forEach(sub => {
list[sub] = true;
});
}
if (parent.sub_departments && parent.sub_departments.length) {
let checkParent = true;
for (const subItem of parent.sub_departments) {
if (!list[subItem]) {
checkParent = false;
break;
}
}
if (checkParent) {
list[parent.department] = true;
}
}
}
return list;
});
};
return (
<List>
{data.map((department) => (
<React.Fragment key={department.department}>
<ListItem
sx={{ cursor: "pointer" }}
onClick={() => handleClick(department.department)}
>
<Checkbox
checked={checked[department.department] || false}
onChange={() => handleCheck(department)}
/>
<ListItemText primary={department.department} />
{open[department.department] ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open[department.department]} unmountOnExit>
<List
component="div"
sx={{ padding: "0 35px", cursor: "pointer" }}
disablePadding
>
{department.sub_departments.map((subDepartment) => (
<ListItem key={subDepartment}>
<Checkbox
checked={checked[subDepartment] || false}
onChange={() => handleCheck({ department: subDepartment }, department)}
/>
<ListItemText primary={subDepartment} />
</ListItem>
))}
</List>
</Collapse>
</React.Fragment>
))}
</List>
);
};
ReactDOM.createRoot(document.getElementById('app')).render(
<DropDownList
data={[
{
department: 'Fruit',
sub_departments: ['apple', 'pear', 'orange'],
},
{
department: 'Colors',
sub_departments: ['Red', 'Green', 'Blue'],
},
]}
/>
);
英文:
For "select all the sub-items if the main head is checked", consider modifying handleCheck()
to pass an item
object. This will let us know of the checked item's sub_departments
:
const handleCheck = (item) => {
setChecked((prevChecked) => ({
...prevChecked,
[item.department]: !prevChecked[item.department],
}));
};
…
<Checkbox
…
onChange={() => handleCheck(department)}
/>
…
<Checkbox
…
onChange={() => handleCheck({ department: subDepartment })}
/>
If it is being checked, check its sub_departments
:
const handleCheck = (item, parent = {}) => {
setChecked((prevChecked) => {
const list = {
...prevChecked,
[item.department]: !prevChecked[item.department],
};
if (list[item.department]) {
if (item.sub_departments) {
item.sub_departments.forEach(sub => {
list[sub] = true;
});
}
}
return list;
});
};
For "select the head, if all the sub-items are checked", pass in the parent department item as a second argument to handleCheck()
:
const handleCheck = (item, parent = {}) => {
…
}
…
<Checkbox
…
onChange={() => handleCheck({ department: subDepartment }, department)}
/>
Then check the parent department if all the sub_departments
are checked:
const handleCheck = (item, parent = {}) => {
setChecked((prevChecked) => {
const list = {
...prevChecked,
[item.department]: !prevChecked[item.department],
};
if (list[item.department]) {
…
if (parent.sub_departments && parent.sub_departments.length) {
let checkParent = true;
for (const subItem of parent.sub_departments) {
if (!list[subItem]) {
checkParent = false;
break;
}
}
if (checkParent) {
list[parent.department] = true;
}
}
}
return list;
});
};
Full example:
<!-- begin snippet: js hide: false console: false babel: true -->
<!-- language: lang-js -->
const { useState } = React;
const { List, ListItem, Checkbox, ListItemText, Collapse } = MaterialUI;
const ExpandMore = () => 'ExpandMore';
const ExpandLess = () => 'ExpandLess';
const DropDownList = ({ data }) => {
const [open, setOpen] = useState({});
const [checked, setChecked] = useState({});
const handleClick = (department) => {
setOpen((prevOpen) => ({
...prevOpen,
[department]: !prevOpen[department],
}));
};
const handleCheck = (item, parent = {}) => {
setChecked((prevChecked) => {
const list = {
...prevChecked,
[item.department]: !prevChecked[item.department],
};
if (list[item.department]) {
if (item.sub_departments) {
item.sub_departments.forEach(sub => {
list[sub] = true;
});
}
if (parent.sub_departments && parent.sub_departments.length) {
let checkParent = true;
for (const subItem of parent.sub_departments) {
if (!list[subItem]) {
checkParent = false;
break;
}
}
if (checkParent) {
list[parent.department] = true;
}
}
}
return list;
});
};
return (
<List>
{data.map((department) => (
<React.Fragment key={department.department}>
<ListItem
sx={{ cursor: "pointer" }}
onClick={() => handleClick(department.department)}
>
<Checkbox
checked={checked[department.department] || false}
onChange={() => handleCheck(department)}
/>
<ListItemText primary={department.department} />
{open[department.department] ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open[department.department]} unmountOnExit>
<List
component="div"
sx={{ padding: "0 35px", cursor: "pointer" }}
disablePadding
>
{department.sub_departments.map((subDepartment) => (
<ListItem key={subDepartment}>
<Checkbox
checked={checked[subDepartment] || false}
onChange={() => handleCheck({ department: subDepartment }, department)}
/>
<ListItemText primary={subDepartment} />
</ListItem>
))}
</List>
</Collapse>
</React.Fragment>
))}
</List>
);
};
ReactDOM.createRoot(document.getElementById('app')).render(
<DropDownList
data={[
{
department: 'Fruit',
sub_departments: ['apple', 'pear', 'orange'],
},
{
department: 'Colors',
sub_departments: ['Red', 'Green', 'Blue'],
},
]}
/>
);
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js" integrity="sha512-8Q6Y9XnTbOE+JNvjBQwJ2H8S+UV4uA6hiRykhdtIyDYZ2TprdNmWOUaKdGzOhyr4dCyk287OejbPvwl7lrfqrQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js" integrity="sha512-MOCpqoRoisCTwJ8vQQiciZv0qcpROCidek3GTFS6KTk2+y7munJIlKCVkFCYY+p3ErYFXCjmFjnfTTRSC1OHWQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://unpkg.com/@mui/material@v5.14.1/umd/material-ui.development.js"></script>
<div id="app"></div>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论