【问题标题】:How to 'Indeterminate' checkboxs?如何“不确定”复选框?
【发布时间】:2021-11-16 09:37:49
【问题描述】:

您好,我想知道如何将“Indeterminate”应用于我的代码复选框示例:

我知道文档就在那里,但我无法让它发挥作用这是我的尝试,我想说我很接近但显然错过了一些非常重要的东西

这个想法是,当我单击“父级”时,所有这些都被单击,所有这些都更改为已选中,并且它们都将数据发送到一个变量,当我取消单击时,它们应该将其删除,当我删除时一个特别是它应该只删除那个特别的(那个已经在工作,但是如果我必须为父级添加其他东西,那就不行了)

他们每个人都做我想做的事,但我想添加父/主,所以我可以检查所有这些:

这是我的代码:

[根据我目前收到的帮助编辑代码]

//Functions

//set all students
const [allStudentsID, setAllStudentsID] = useState([]);
const setAllStudents = () => {
  setAllStudentsID(Array.isArray(estudiantes) ? allStudentsID.length && estudiantes.length === allStudentsID.length ? [] : estudiantes.map(x=> x.id):[]);
  console.log(allStudentsID)
}

console.log 如下所示:

//set individual one by one (works)
const [studentID, setStudentID] = useState([])
const setStudent = (estudiante) => {
  if(!studentID.find(id => id === estudiante)){
    setStudentID([ ... studentID, estudiante]); 
 }  
  else {
   setStudentID(studentID.filter(studentId => studentId !== estudiante)) 
   }  

   console.log(studentID)
}
Mapping/Render:

//Titles (not sure if I'm setting up correctly the checkbox)
                <thead>

                    <tr className="Lista">
                        <Checkbox 
                        color = "primary" 
                        id = "checkBox" 
                        onChange = {() => setAllStudents()}
                        checked={allStudentsID.length === estudiantes.length}
                        indeterminate={allStudentsID.length > 0 && allStudentsID.length < estudiantes.length}
                        />

                        <th>Nombre</th>
                        <th>Colegio</th>
                        <th>Grado</th>
                        <th>Accion</th>
                    </tr>
                </thead>

//Table (this works)
{estudiantes.map((estudiantes, index) => (
                <tr key={estudiantes.id || index}>
                <td>
                <Checkbox
                checked={!!studentID.find( id => id === estudiantes.uid)}
                color = "primary"
                id = "checkBox"
                onChange = {() => setStudent(estudiantes.uid, index)}
                inputProps={{ 'aria-label': 'controlled' }}
                />
                </td>

... some code that will finish the table

【问题讨论】:

  • 如果你使用的是 MUI,那么你应该看看 DataGrid 组件

标签: reactjs checkbox material-ui


【解决方案1】:

根据您的代码和问题,当您使用estudiantes.uid 处理复选框状态时,它可以工作,但在setAllStudents 函数中,您使用的是x.label,它不存在于数组中,这就是您的控制台日志显示undefined 的原因。也许尝试更新函数以从函数返回id

将状态初始化为一个空数组

const [allStudentsID, setAllStudentsID] = useState([]);

如果所有复选框都已选中,则更新setAllStudents 以检查这两个条件,而不是将状态数组重置为空数组,否则选择全部。

const setAllStudents = () => {
  setAllStudentsID(Array.isArray(estudiantes) ? allStudentsID.length && estudiantes.length === allStudentsID.length ? [] : estudiantes.map(x=> x.id):[]);
  console.log(allStudentsID)
}

还请在标题中的复选框中提供checkedindeterminate 属性。

<Checkbox 
  color = "primary" 
  id = "checkBox" 
  onChange = {() => setAllStudents()}
  checked={allStudentsID.length === estudiantes.length} // if both are equal, that means all were already selected
  indeterminate={allStudentsID.length > 0 && allStudentsID.length < estudiantes.length}
/>

【讨论】:

  • 它确实解决了与将变量保存到.uid相关的部分,但仍然无法将父复选框与子复选框连接起来,这是“不确定”的整个问题
  • 在父复选框中,您还需要传递 checkedindeterminate 属性。基本上你需要使用一个状态数组来存储复选框状态。保持子复选框的功能不变。我正在更新父复选框代码的答案。
  • 奇怪的是我收到一个错误'allStudentID' is not defined 这没有意义......
  • 希望,它现在可以工作了。我已经更新了答案,在Checkbox 的道具部分有一个错字allStudentID
  • 正确的“s”没有注意到,正在抓取所有值并在之后取消选择所有值,但其他检查没有像示例中那样得到检查,这比我虽然。
【解决方案2】:

我从头开始编写代码:

代码中的注释。

CodeSandbox

import { Fragment, useState } from "react";
import Box from "@mui/material/Box";
import Checkbox from "@mui/material/Checkbox";
import { Card } from "@mui/material";

const estudiantes = [
  { uid: 1, label: "Student 1" },
  { uid: 2, label: "Student 2" },
  { uid: 3, label: "Student 3" }
];

const App = () => {
  const [checkedStudents, setCheckedStudents] = useState([]);

  const handleChange1 = (isChecked) => {
    if (isChecked)
      return setCheckedStudents(
        estudiantes.map((estudiante) => estudiante.uid)
      );
    else setCheckedStudents([]);
  };

  const handleChange2 = (isChecked, uid) => {
    const index = checkedStudents.indexOf(uid);

    // The checked value is altered before the state changes for some reason is not a trully controlled component
    // So the next conditions are INVERTED.

    if (isChecked) return setCheckedStudents((state) => [...state, uid]);

    if (!isChecked && index > -1)
      return setCheckedStudents((state) => {
        state.splice(index, 1);
        return JSON.parse(JSON.stringify(state)); // Here's the trick => React does not update the f* state array changes even with the spread operator, the reference is still the same.
      });
  };

  return (
    <Fragment>
      {/* Parent */}

      <Checkbox
        checked={checkedStudents.length === estudiantes.length}
        indeterminate={
          checkedStudents.length !== estudiantes.length &&
          checkedStudents.length > 0
        }
        onChange={(event) => handleChange1(event.target.checked)}
      />

      {/* Childrens */}
      <Box sx={{ display: "flex", flexDirection: "column", ml: 3 }}>
        {checkedStudents &&
          estudiantes.map((estudiante) => (
            <Checkbox
              key={estudiante.uid}
              checked={checkedStudents.includes(estudiante.uid)}
              onChange={(event) =>
                handleChange2(event.target.checked, estudiante.uid)
              }
              inputProps={{ "aria-label": "controlled" }}
            />
          ))}
      </Box>

      <h3>ID's: {JSON.stringify(checkedStudents)}</h3>
    </Fragment>
  );
};

export default App;

【讨论】:

    【解决方案3】:

    我找到了一个解决方案,但必须更改为常规复选框,然后将这个主题保留一半解决,因为到目前为止我们还没有找到一个解决方案来正确使用 Material UI 复选框,我将把它留在这里这是为了常规输入复选框。

    //Variable that will provide the data (mine updates from firebase so not gonna add all that code)
    const [estudiantes, setEstudiantes] = useState([]);
    
    //Variable that will hold all the data
    const [studentsID, setStudentsID] = useState([]);
    
    //Function
    const handleChange = (e, data) => {
      const { name, checked } = e.target;
      if (checked) {
        // if cheked and selectall checkbox add all fileds to selectedList
        if (name === "allSelect") {
          setStudentsID(estudiantes);
        } else {
          // if cheked and specific checkbox add specific field to selectedList
          setStudentsID([...studentsID, data]);
        }
      } else {
        // if uncheked and selectall checkbox add remove all fileds from selectedList
        if (name === "allSelect") {
          setStudentsID([]);
        } else {
          // if uncheked and specific checkbox remove specific field from selectedList
          let tempuser = studentsID.filter((item) => item.id !== data.id);
          setStudentsID(tempuser);
        }
      }
      console.log(studentsID)
    };
    
    //Main select checkbox
    <input
       type="checkbox"
       className="form-check-input"
       name="allSelect"
       checked={studentsID?.length === estudiantes?.length}
       onChange={(e) => handleChange(e, estudiantes)}
    />
    
    //Checkboxs inside the .map
    
    <tbody>
    {estudiantes.map((estudiantes, index) => (
       <tr key={estudiantes.id || index}>
       <td>
          <input
          type="checkbox"
          className="form-check-input"
          name={estudiantes.uid}
          checked={studentsID.some((item) => item?.uid === estudiantes.uid)}
          onChange={(e) => handleChange(e, estudiantes)}
          />
       </td>
    
    //Some nonrelevant code for this question ...
    
    };
    

    免责声明这个答案不是我的,我是从教程中找到的:All Select Checkbox in React JS 和一个示例:Example 我只是根据自己的需要调整了它。

    如果有人使用 Material UI 复选框找到合适的解决方案,请告诉我。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-12
      • 1970-01-01
      • 2016-10-31
      • 2020-05-04
      相关资源
      最近更新 更多