Как «Неопределить» чекбоксы?

#reactjs #checkbox #material-ui

Вопрос:

Здравствуйте, я хочу знать, как применить «Неопределенный» к моему примеру флажка кода:

введите описание изображения здесь

Я знаю, что документация там есть, но я не смог заставить ее работать, это была моя попытка, и я бы сказал, что был близок, но явно упустил что-то очень важное

введите описание изображения здесь

Идея заключается в том, что когда я нажимаю на «родительский», все они нажимаются, все они меняются на «проверено», и все они отправляют данные в переменную, и когда я снимаю клик, они должны удалить его, а когда я удаляю один, в частности, он должен удалить только этот (этот уже работает, но idk, если мне нужно добавить что-то еще для родителя).

По отдельности они делают то, что я хочу, но я хотел добавить родительский/основной, чтобы я мог просто проверить их все:

введите описание изображения здесь

Это мой код:

[Отредактированный код, основанный на помощи, которую я получил до сих пор]

 //Functions

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

Консоль.журнал выглядит так:

введите описание изображения здесь

 //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 amp;amp; 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
 

Комментарии:

1. Если вы используете MUI, то вам следует взглянуть на DataGrid компонент

Ответ №1:

В соответствии с вашим кодом и вопросом, когда вы используете estudiantes.uid для обработки состояния флажков, это работает, но в setAllStudents функции, которую вы используете x.label , которой нет в массиве, поэтому в журнале вашей консоли отображается undefined . Может быть, попробуйте обновить функцию, чтобы вернуть id из функции.

Инициализируйте состояние как массив emtpy

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

Чем обновлять setAllStudents , чтобы проверить оба условия, если все флажки уже установлены, чем сбросить массив состояний в пустой массив, в противном случае выберите все.

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

Пожалуйста, также укажите checked и indeterminate реквизиты для флажка в заголовке.

 <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 amp;amp; allStudentsID.length < estudiantes.length}
/> 

Комментарии:

1. это действительно решает часть, связанную с сохранением переменных, которые просто необходимо было .uid сохранить, но все еще не удается подключить родительский флажок с детьми, что является целым вопросом «неопределенного».

2. В родительском флажке вам также нужно передать checked и indeterminate реквизиты. В основном вам нужно использовать один массив состояний для хранения состояния флажков. сохраните функциональность дочерних флажков в том виде, в каком она есть. Я обновляю ответ для кода родительского флажка.

3. странно то, что я получаю ошибку 'allStudentID' is not defined , которая не имеет смысла…

4. Надеюсь, теперь это работает. Я обновил ответ, в котором была опечатка allStudentID в разделе «Реквизит Checkbox «.

5. Правильно, «s» на нем не заметил, захватывает все значения и отменяет их выбор после этого, но другие проверки не проверяются, как в примере, это сложнее, чем я думал.

Ответ №2:

Я нашел решение, но мне пришлось переключиться на обычный флажок, который затем оставляет эту тему наполовину решенной, потому что до сих пор мы не нашли решения, чтобы сделать это правильно с помощью флажка 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 ...

};
 

Отказ от ответственности этот ответ не мой, я нашел его в учебнике: Все установите флажок в React JS и пример: Пример Я просто адаптировал его к своим потребностям.

Если кто-нибудь найдет правильное решение с флажком Material UI, дайте мне знать.

Ответ №3:

Я создал код с нуля:

Комментарии в коде.

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 amp;amp; 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 amp;amp;
          checkedStudents.length > 0
        }
        onChange={(event) => handleChange1(event.target.checked)}
      />

      {/* Childrens */}
      <Box sx={{ display: "flex", flexDirection: "column", ml: 3 }}>
        {checkedStudents amp;amp;
          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;