Home > Mobile >  how to disable a button if more than one or no checkbox is checked in React JS
how to disable a button if more than one or no checkbox is checked in React JS

Time:11-22

I have a table where the first column has a checkbox in each row. I want to disable a button if more than one checkbox is selected or no check box is checked. It should be active only if 1 checkbox is checked

import React, { useState } from "react";
import "./styles.css";
function Example() {
  const [boxes, setBoxes] = useState([]);
  function handleChange(e) {
    const {
      parentNode: { children }
    } = e.target;
    const index = [...children].indexOf(e.target);
    const newState = [...boxes];
    newState[index] = !newState[index];
    setBoxes(newState);
  }
  function isDisabled() {
    const len = boxes.filter((box) => box).length;
    return len === 0 || len > 1;
  }
  return (
    <div className="App">
      <button disabled={isDisabled()}>Click Me</button>
      <table>
        <thead>
          <th>One</th>
          <th>Two</th>
          <th>Three</th>
        </thead>
        <tbody>
          <tr>
            <td>
              <input type="checkbox" onChange={handleChange} />
            </td>
            <td> two data</td>
            <td> three data</td>
          </tr>
          <tr>
            <td>
              <input type="checkbox" onChange={handleChange} />
            </td>
            <td> two data</td>
            <td> three data</td>
          </tr>
          <tr>
            <td>
              <input type="checkbox" onChange={handleChange} />
            </td>
            <td> two data</td>
            <td> three data</td>
          </tr>
        </tbody>
      </table>
    </div>
  );
}

export default Example;

I was able to make this work if all the checkboxes are in the same parent node. But in the case of a table, each checkbox is in a separate row.

CodePudding user response:

You can assign ids to the checkboxes and follow them like this.

import React, { useState } from "react";
function Example() {
  const [boxes, setBoxes] = useState({});
  function handleChange(e) {
    const {
      target: { id, checked }
    } = e;
    setBoxes({ ...boxes, [id]: checked });
  }
  function isDisabled() {
    const { length } = Object.values(boxes).filter(Boolean);
    return length !== 1;
  }
  return (
    <div className="App">
      <button disabled={isDisabled()}>Click Me</button>
      <table>
        <thead>
          <th>One</th>
          <th>Two</th>
          <th>Three</th>
        </thead>
        <tbody>
          <tr>
            <td>
              <input id="1" type="checkbox" onChange={handleChange} />
            </td>
            <td> two data</td>
            <td> three data</td>
          </tr>
          <tr>
            <td>
              <input id="2" type="checkbox" onChange={handleChange} />
            </td>
            <td> two data</td>
            <td> three data</td>
          </tr>
          <tr>
            <td>
              <input id="3" type="checkbox" onChange={handleChange} />
            </td>
            <td> two data</td>
            <td> three data</td>
          </tr>
        </tbody>
      </table>
    </div>
  );
}

export default Example;

CodePudding user response:

You can give them all the checkboxes one name and this solution will work just fine

    import React, { useState } from "react";
function Example() {
  const [btnStatus, setBtnStatus] = useState(true);
  function handleChange(e) {
    const elements = document.getElementsByName('checkbox');
    let checkedCount = 0;
    elements.forEach((element)=>{
      if(element.checked){
        checkedCount   ;
      }
    })
  if(checkedCount > 1 || checkedCount === 0){
    setBtnStatus(true)
  }else{
    setBtnStatus(false)
  }
  }

  return (
    <div className="App">
      <button disabled={btnStatus}>Click Me</button>
      <table>
        <thead>
          <th>One</th>
          <th>Two</th>
          <th>Three</th>
        </thead>
        <tbody>
          <tr>
            <td>
              <input name="checkbox" type="checkbox" onChange={handleChange} />
            </td>
            <td> two data</td>
            <td> three data</td>
          </tr>
          <tr>
            <td>
              <input name="checkbox" type="checkbox" onChange={handleChange} />
            </td>
            <td> two data</td>
            <td> three data</td>
          </tr>
          <tr>
            <td>
              <input name="checkbox" type="checkbox" onChange={handleChange} />
            </td>
            <td> two data</td>
            <td> three data</td>
          </tr>
        </tbody>
      </table>
    </div>
  );
}

export default Example;

CodePudding user response:

Your initial test (with all checkboxes in the same parent node) was working because you are relying that they are all in the same parent node here:

const {
  parentNode: { children }
} = e.target;

where "children" are the actual checkboxes. In the table example, each checkbox's parent has only one child.

I would suggest a more flexible solution like below, sending the checkbox index as a parameter to the onChange handler:

import React, { useState } from "react";

// use props to determine the number of records
function Example(props) {
  // make sure initial state is known and false
  const [boxes, setBoxes] = useState(new Array(props.recordsNo).fill(false));

  // index - the index of the checkbox
  function handleChange(index) {
    const newState = [...boxes];
    newState[index] = !newState[index];
    setBoxes(newState);
  }
  
  function isDisabled() {
    const len = boxes.filter((box) => box).length;
    return len === 0 || len > 1;
  }

  // records will probably come through props => generate here an example
  const records = [...Array(props.recordsNo).keys()];
  
  // generate records display 
  const rows = records.map((value, i) => {
    return (
      <tr>
        <td>
          <input type="checkbox" onChange={() => handleChange(i)} />
        </td>
        <td> {i}</td>
        <td> two data</td>
        <td> three data</td>
      </tr>
    )
  })

  return (
    <div className="App">
      <button disabled={isDisabled()}>Click Me</button>
      <table>
        <thead>
          <th>One</th>
          <th>Two</th>
          <th>Three</th>
        </thead>
        <tbody>
          {rows}
        </tbody>
      </table>
    </div>
  );
}

export default Example;
  • Related