Home > Software design >  How to 'Indeterminate' checkboxs?
How to 'Indeterminate' checkboxs?

Time:09-23

Hello I want to know how to apply "enter image description here

I know the documentation is right there but I wasn't able to make it work this was my attempt and I would say I was close but clearly missing something very important

enter image description here

The idea is that when I click the "parent" one all of them get clicked, all of them changed to checked and all of them send the data to a variable and when I unclick they should remove it, and when I remove one in particular it should only remove that one in particular (that one is already working but idk if I have to add something else for the parent)

Individually they do what I want but I wanted to add the parent/main one so I can just check all of them:

enter image description here

This is my code:

//Functions

//set all students attempt
const [allStudentsID, setAllStudentsID] = useState();
const setAllStudents = () => {
  setAllStudentsID(Array.isArray(estudiantes)?estudiantes.map(x=> x.label):[]);
  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">
                        <th ><Checkbox 
                              color = "primary" 
                              id = "checkBox" 
                              onChange = {() => setAllStudents()}
                              />
                        </th>
                        <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

CodePudding user response:

As per your code and question, when you're using estudiantes.uid to handle the checkboxes state, it works, but in setAllStudents function, you're usingx.label, which doesn't exist in the array, that's why your console log shows the undefined. Maybe try updating the function to return the id from the function.

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

CodePudding user response:

I encountered many problems using MUI.

I made this code for you, hope it helps:

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={Math.random()}
              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;
  • Related