Home > Back-end >  checkbox functionality using react with typescript
checkbox functionality using react with typescript

Time:04-18

How to make the checkbox such that if the header checkbox is checked then all other checkboxes will be checked and unchecked if all other checkboxes will be unchecked? Also if other checkboxes are selected then the header checkbox should be undeterminate using react with typescript?

I have the following code in App.tsx

import React, {useState} from "react";
import { useQuery } from "react-query";
import { GraphQLClient, gql } from "graphql-request";
import "./index.css";
import Button from "./Components/Button";


const API_URL = `https://graphqlzero.almansi.me/api`;

const graphQLClient = new GraphQLClient(API_URL, {
  headers: {
    Authorization: `Bearer ${process.env.API_KEY}`,
  },
});


export function useGetPosts() {
  return useQuery("get-posts", async () => {
    const {
      users: { data },
    } = await graphQLClient.request(gql`
      {
        users {
          data {
            id
            name
            username
            email
            address {
              street
            }
            phone
            website
          }
        }
      }
    `);
    return data;
  });
}
const App = () => {
  const [checked, setChecked] = useState(false)
  const handleClick = () => setChecked(!checked)
  const response = useGetPosts();
  const { data } = response;
  console.log({ response });

  //   address: {street: 'Kulas Light'}
  // email: "[email protected]"
  // id: "1"
  // name: "Leanne Graham"
  // phone: "1-770-736-8031 x56442"
  // username: "Bret"
  // website: "hildegard.org"
  return (
    <div>
     
      <section>
        <div className="header">Users
        <form>
          <input
            type="text"
              placeholder="Search Here" />
            
           
            
          </form>
          <Button name = "New User" />
           
          </div>
        <header>
         
          <div className="col" >
            <input
              onClick={handleClick} checked={checked}
              type="checkbox"
              className = "column"
            />
          </div>
          <div className="col">Name</div>
          <div className="col">Username</div>
          <div className="col">Email</div>
          <div className="col">Phone</div>
          <div className="col">Website</div>
          <div className="col">Address</div>
        </header>
        {data?.map((item: any) => (
          <>
            
            <div className="row">
              <div className="col">
                <input
                  onClick={handleClick} checked={checked}
                  type="checkbox" />
              </div>
              <div className="col">{item?.name}</div>
              <div className="col">{item?.username}</div>
              <div className="col">{item?.email}</div>
              <div className="col">{item?.phone}</div>
              <div className="col">{item?.website}</div>
              <div className="col">{item?.address?.street}</div>
            </div>
          </>
        ))}
      </section>
    </div>
  );
};

export default App;

CodePudding user response:

This example may help you: https://chakra-ui.com/docs/components/form/checkbox#indeterminate

Basically, there're only 2 rules like you listed:

  • The header checkbox is checked only if all other checkboxes are checked (we test this by using .every())
  • The header checkbox is indeterminate only if there are just some checkboxes are checked (we test this by using .some())

CodePudding user response:

I noticed that you have the same onClick function for both the header input and the children inputs. In order to make this work, we need to create another handleClick function for the children inputs.

  1. Create an array of boolean values

    const isCheckedData = data.map((item)=>{ return false; });

  2. Add another state which would hold this array

    const [isCheckedArray, setIsCheckedArray] = useState(isCheckedData);

  3. Distribute the values of the array to your mapped data below

{data?.map((item: any, index) => ( <>

        <div className="row">
          <div className="col">
            <input
              onClick={() => handleClickChildren(index)} checked={isCheckedArray[index]}
              type="checkbox" />
          </div>
          <div className="col">{item?.name}</div>
          <div className="col">{item?.username}</div>
          <div className="col">{item?.email}</div>
          <div className="col">{item?.phone}</div>
          <div className="col">{item?.website}</div>
          <div className="col">{item?.address?.street}</div>
        </div>
      </>
    ))}
  1. Create a function that will take the index as an argument so that we could change the value of a specific checkbox in our state.

const handleClickChildren = (index) => {
const findCheckBox = isCheckedArray.find(data=>isCheckedArray. indexOf(data)===index);
const newCheckedArray = isCheckedArray.splice(isCheckedArray.indexOf(findCheckBox), 1, !findCheckBox);
setIsCheckedArray(newCheckedArray);

Check the docs for splice for more info, but basically what that does is it just replaces the previous value to true or false. https://www.w3schools.com/jsref/jsref_splice.asp

5.) Lastly, Refactor your first handleOnClick function to change the state of the isCheckedArray depending if the header checkbox is set to true or false.

CodePudding user response:

Example in javascript, with react where you have the functionality that you want.

import React, { useEffect, useState } from 'react';

const CHECKBOX_VALUES = [false, false];

function Question16() {
  const [checkboxValues, setCheckboxValues] = useState(CHECKBOX_VALUES);
  const checkboxRef = React.useRef(null);

  const onCheck = (pos, value) => {
    const nextCheckboxValues = [ ...checkboxValues ];
    nextCheckboxValues[pos] = value;
    setCheckboxValues(nextCheckboxValues);
  }

  useEffect(() => {
    const isIndeterminate = checkboxRef.current.indeterminate;
    const someCheckboxChecked = checkboxValues.some((checkValue) => checkValue);
    const someCheckboxUnchecked = checkboxValues.some((checkValue) => !checkValue);
    const nextIndeterminate = someCheckboxChecked && someCheckboxUnchecked;
    if (isIndeterminate !== nextIndeterminate) {
      checkboxRef.current.indeterminate = nextIndeterminate;
    }
    if (!nextIndeterminate) {
      checkboxRef.current.checked = someCheckboxChecked;
    }
  }, [checkboxValues]);
  
  return (
    <>
      <div>
        <span>Parent checkbox</span>
        <input type="checkbox" ref={checkboxRef} />
      </div>
      <div>
        <span>Checkbox 1</span>
        <input
          checked={checkboxValues[0]}
          onChange={(elem) => {
              const value = elem.target.checked;
              onCheck(0, value);
          }}
          type="checkbox"
        />
      </div>
      <div>
        <span>Checkbox 2</span>
        <input
          checked={checkboxValues[1]}
          onChange={(elem) => {
            const value = elem.target.checked;
            onCheck(1, value);
          }}
          type="checkbox"
        />
      </div>
    </>
  );
}

export default Question16;

  • Related