如何在选中主标题时检查所有子项目,反之亦然?

huangapple go评论72阅读模式
英文:

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) =&gt; {
  setChecked((prevChecked) =&gt; ({
    ...prevChecked,
    [item.department]: !prevChecked[item.department],
  }));
};

&lt;Checkbox
  
  onChange={() =&gt; handleCheck(department)}
/&gt;

&lt;Checkbox
  
  onChange={() =&gt; handleCheck({ department: subDepartment })}
/&gt;

If it is being checked, check its sub_departments:

const handleCheck = (item, parent = {}) =&gt; {
  setChecked((prevChecked) =&gt; {
    const list = {
      ...prevChecked,
      [item.department]: !prevChecked[item.department],
    };

    if (list[item.department]) {
      if (item.sub_departments) {
        item.sub_departments.forEach(sub =&gt; {
          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 = {}) =&gt; {
  
}

&lt;Checkbox
  
  onChange={() =&gt; handleCheck({ department: subDepartment }, department)}
/&gt;

Then check the parent department if all the sub_departments are checked:

const handleCheck = (item, parent = {}) =&gt; {
  setChecked((prevChecked) =&gt; {
    const list = {
      ...prevChecked,
      [item.department]: !prevChecked[item.department],
    };

    if (list[item.department]) {
      
      if (parent.sub_departments &amp;&amp; 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 = () =&gt; &#39;ExpandMore&#39;;
const ExpandLess = () =&gt; &#39;ExpandLess&#39;;
const DropDownList = ({ data }) =&gt; {
const [open, setOpen] = useState({});
const [checked, setChecked] = useState({});
const handleClick = (department) =&gt; {
setOpen((prevOpen) =&gt; ({
...prevOpen,
[department]: !prevOpen[department],
}));
};
const handleCheck = (item, parent = {}) =&gt; {
setChecked((prevChecked) =&gt; {
const list = {
...prevChecked,
[item.department]: !prevChecked[item.department],
};
if (list[item.department]) {
if (item.sub_departments) {
item.sub_departments.forEach(sub =&gt; {
list[sub] = true;
});
}
if (parent.sub_departments &amp;&amp; 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 (
&lt;List&gt;
{data.map((department) =&gt; (
&lt;React.Fragment key={department.department}&gt;
&lt;ListItem
sx={{ cursor: &quot;pointer&quot; }}
onClick={() =&gt; handleClick(department.department)}
&gt;
&lt;Checkbox
checked={checked[department.department] || false}
onChange={() =&gt; handleCheck(department)}
/&gt;
&lt;ListItemText primary={department.department} /&gt;
{open[department.department] ? &lt;ExpandLess /&gt; : &lt;ExpandMore /&gt;}
&lt;/ListItem&gt;
&lt;Collapse in={open[department.department]} unmountOnExit&gt;
&lt;List
component=&quot;div&quot;
sx={{ padding: &quot;0 35px&quot;, cursor: &quot;pointer&quot; }}
disablePadding
&gt;
{department.sub_departments.map((subDepartment) =&gt; (
&lt;ListItem key={subDepartment}&gt;
&lt;Checkbox
checked={checked[subDepartment] || false}
onChange={() =&gt; handleCheck({ department: subDepartment }, department)}
/&gt;
&lt;ListItemText primary={subDepartment} /&gt;
&lt;/ListItem&gt;
))}
&lt;/List&gt;
&lt;/Collapse&gt;
&lt;/React.Fragment&gt;
))}
&lt;/List&gt;
);
};
ReactDOM.createRoot(document.getElementById(&#39;app&#39;)).render(
&lt;DropDownList
data={[
{
department: &#39;Fruit&#39;,
sub_departments: [&#39;apple&#39;, &#39;pear&#39;, &#39;orange&#39;],
},
{
department: &#39;Colors&#39;,
sub_departments: [&#39;Red&#39;, &#39;Green&#39;, &#39;Blue&#39;],
},
]}
/&gt;
);

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js&quot; integrity=&quot;sha512-8Q6Y9XnTbOE+JNvjBQwJ2H8S+UV4uA6hiRykhdtIyDYZ2TprdNmWOUaKdGzOhyr4dCyk287OejbPvwl7lrfqrQ==&quot; crossorigin=&quot;anonymous&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js&quot; integrity=&quot;sha512-MOCpqoRoisCTwJ8vQQiciZv0qcpROCidek3GTFS6KTk2+y7munJIlKCVkFCYY+p3ErYFXCjmFjnfTTRSC1OHWQ==&quot; crossorigin=&quot;anonymous&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://unpkg.com/@mui/material@v5.14.1/umd/material-ui.development.js&quot;&gt;&lt;/script&gt;
&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年7月23日 14:10:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76746840.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定