skip to Main Content

I am trying to implement a function which will uncheck other checkboxes when a new one is clicked. I am doing this instead of using radio because I want the possibility to uncheck by clicking on the subject.

function uncheck(obj) {
  var ch = document.getElementsByName('ch');
  for (var i = 0; i < ch.length; i++) {
    if (ch[i].id != obj.id) {
      ch[i].checked = !obj.checked;
      break;
    }
  }
}
<input type="checkbox" name="ch" id="Chapter 1" onclick="uncheck(this)">
<input type="checkbox" name="ch" id="Chapter 2" onclick="uncheck(this)">
<input type="checkbox" name="ch" id="Chapter 3" onclick="uncheck(this)">
<input type="checkbox" name="ch" id="Chapter 4" onclick="uncheck(this)">
<input type="checkbox" name="ch" id="Chapter 5" onclick="uncheck(this)">
<input type="checkbox" name="ch" id="Chapter 6" onclick="uncheck(this)">
<input type="checkbox" name="ch" id="Chapter 7" onclick="uncheck(this)">
<input type="checkbox" name="ch" id="Chapter 8" onclick="uncheck(this)">
<input type="checkbox" name="ch" id="Chapter 9" onclick="uncheck(this)">
<input type="checkbox" name="ch" id="Chapter 10" onclick="uncheck(this)">
<input type="checkbox" name="ch" id="Chapter 11" onclick="uncheck(this)">
<input type="checkbox" name="ch" id="Chapter 12" onclick="uncheck(this)">
<input type="checkbox" name="ch" id="Chapter 13" onclick="uncheck(this)">
<input type="checkbox" name="ch" id="Chapter 14" onclick="uncheck(this)">

However, as the function works now, for some reason, if I check chapter 4, and then check chapter 1, it won’t uncheck chapter 4. And when I uncheck chapter 1, for some reason it checks chapter 2, and if I uncheck chapter 2, it checks chapter 1.

5

Answers


  1. Try this one…

    function uncheck(obj) {
      const checkboxes = document.getElementsByName('ch');
      for (let i = 0; i < checkboxes.length; i++) {
        if (checkboxes[i].id !== obj.id) {
          checkboxes[i].checked = false;
        }
      }
    }
    <input type="checkbox" name="ch" id="Chapter 1" onclick="uncheck(this)">
    <input type="checkbox" name="ch" id="Chapter 2" onclick="uncheck(this)">
    <input type="checkbox" name="ch" id="Chapter 3" onclick="uncheck(this)">
    <input type="checkbox" name="ch" id="Chapter 4" onclick="uncheck(this)">
    <input type="checkbox" name="ch" id="Chapter 5" onclick="uncheck(this)">
    <input type="checkbox" name="ch" id="Chapter 6" onclick="uncheck(this)">
    <input type="checkbox" name="ch" id="Chapter 7" onclick="uncheck(this)">
    <input type="checkbox" name="ch" id="Chapter 8" onclick="uncheck(this)">
    <input type="checkbox" name="ch" id="Chapter 9" onclick="uncheck(this)">
    <input type="checkbox" name="ch" id="Chapter 10" onclick="uncheck(this)">
    <input type="checkbox" name="ch" id="Chapter 11" onclick="uncheck(this)">
    <input type="checkbox" name="ch" id="Chapter 12" onclick="uncheck(this)">
    <input type="checkbox" name="ch" id="Chapter 13" onclick="uncheck(this)">
    <input type="checkbox" name="ch" id="Chapter 14" onclick="uncheck(this)">
    Login or Signup to reply.
  2. In the code you provided, you are trying to check/uncheck all of the boxes except the one that is clicked but the break makes it only toggle one.

    function uncheck(obj) {
      let ch = document.getElementsByName("ch");
      for (let i = 0; i < ch.length; i++) {
        if (ch[i].id != obj.id) {
          ch[i].checked = false;
        }
      }
    }
    

    This way, it loops through the entire code setting each checkbox to false except for the one the user clicks on.

    Login or Signup to reply.
  3. If i understand your problem. Then your code is perfectly alright.

    JUST REMOVE BREAK FROM YOUR CODE!

    Like:

    if (ch[i].id != obj.id) {
    ch[i].checked = !obj.checked;
    //break;
    }
    

    Hope it will help….

    Regards
    Shawpnendu
    coderstechzone

    Login or Signup to reply.
  4. You have a break statement in the body of the if: this will stop the loop on the first element that isn’t the clicked one.

    Removing that reveals another issue: all the checkboxes will be set when one is clicked, to the inverse of the clicked one’s state. Checking one unchecks all the others, but unchecking one checks all the others. This is because they are set to the inverse of the clicked boxes state, not to unchecked.

    A not so consequential issue is using var; I will use let/const. Also, for the sake of clarity, I am going to make variable and function names more clear. And reduce the number of boxes.

    Fixing those yields us this:

    function handleClick(current) {
      const boxes = document.getElementsByName('ch');
      for (let i = 0; i < boxes.length; i++) {
        if (boxes[i].id != current.id) {
          boxes[i].checked = false;
        }
      }
    }
    <input type="checkbox" name="ch" id="Chapter 1" onclick="handleClick(this)">
    <input type="checkbox" name="ch" id="Chapter 2" onclick="handleClick(this)">
    <input type="checkbox" name="ch" id="Chapter 3" onclick="handleClick(this)">
    <input type="checkbox" name="ch" id="Chapter 4" onclick="handleClick(this)">

    That works.

    Simplify using iterators

    But it can be improved using iterators! The getElementsByName method returns a NodeList, which is iterable; because of this, we can use a for...of loop.

    function handleClick(current) {
      const boxes = document.getElementsByName('ch');
      for (box of boxes) {
        if (box.id != current.id) {
          box.checked = false;
        }
      }
    }
    <input type="checkbox" name="ch" id="Chapter 1" onclick="handleClick(this)">
    <input type="checkbox" name="ch" id="Chapter 2" onclick="handleClick(this)">
    <input type="checkbox" name="ch" id="Chapter 3" onclick="handleClick(this)">
    <input type="checkbox" name="ch" id="Chapter 4" onclick="handleClick(this)">

    Tada! Much simpler and clearer.

    Alternative algorithm

    This is the alternative algorithm I suggested: save the state of the clicked box, clear everything, and then set the state of the clicked box.

    function handleClick(current) {
      const boxes = document.getElementsByName('ch');
    
      const wasChecked = current.checked;
      for (box of boxes) {
        box.checked = false;
      }
      current.checked = wasChecked;
    }
    <input type="checkbox" name="ch" id="Chapter 1" onclick="handleClick(this)">
    <input type="checkbox" name="ch" id="Chapter 2" onclick="handleClick(this)">
    <input type="checkbox" name="ch" id="Chapter 3" onclick="handleClick(this)">
    <input type="checkbox" name="ch" id="Chapter 4" onclick="handleClick(this)">

    That satisfies me as to the core algorithm code.

    Some other improvements

    Some other improvements…

    Move the definition of boxes out of the handler, so it isn’t recalculated on every click:

    const boxes = document.getElementsByName('ch');
    
    // ...
    
    function handleClick(current) {
    

    Use addEventListener instead of event attributes (assuming the HTML is static):

    boxes.forEach(box => box.addEventListener("click", handleClick))
    

    Use the proper change event instead of click.

    All in all:

    const boxes = document.getElementsByName('ch');
    
    boxes.forEach(box => box.addEventListener("change", handle))
        
    function handle(event) {
      const wasChecked = event.target.checked;
      for (box of boxes) {
        box.checked = false;
      }
      event.target.checked = wasChecked;
    }
    <input type="checkbox" name="ch" id="Chapter 1">
    <input type="checkbox" name="ch" id="Chapter 2">
    <input type="checkbox" name="ch" id="Chapter 3">
    <input type="checkbox" name="ch" id="Chapter 4">

    Just use radios

    Instead of the above, why not use radios? They’re designed for your use case. You said that you "want the possibility to uncheck by clicking on the subject." You can add that to radios. Maybe not easier for you, but less confusing for your users.

    This does mean you’ll have to use the click event instead of the change or input events (as far as I can tell). But that is insignificant.

    You will need to record the previous state to detect if the click is on an already selected radio.

    const boxes = document.getElementsByName('ch');
    
    boxes.forEach(box => box.dataset.checked = false)
    boxes.forEach(box => box.addEventListener("click", handle))
    
    function handle(event) {
      const wasChecked = event.target.dataset.checked == "true";
      for (box of boxes) {
        box.checked = false;
        box.dataset.checked = false;
      }
      event.target.checked = !wasChecked;
      event.target.dataset.checked = !wasChecked;
    }
    <input type="radio" name="ch" value="Chapter 1">
    <input type="radio" name="ch" value="Chapter 2">
    <input type="radio" name="ch" value="Chapter 3">
    <input type="radio" name="ch" value="Chapter 4">
    Login or Signup to reply.
  5. Quoting the OP …

    I am trying to implement a function which will uncheck other checkboxes when a new one is clicked. I am doing this instead of using radio because I want the possibility to uncheck by clicking on the subject.

    From my above comment …

    @Ryochi … If you want to be able to uncheck a radio-control from a radio-group you should implement it exactly that way. Why? Because with radio-controls and radio-groups you already get all the expected/desired behavior for free except the unchecking of all of a radio-group’s radio-controls; Second, implementing the behavior of a radio-group based on checkbox-controls is more complex than enabling the uncheck-behavior of a radio-group and third, a user expects a certain behavior from checkboxes; a radio-control like switching is the last what the user does expect.

    The next provided example code implements a generic approach for unchecking any radio-group’s last checked radio-control …

    function enableRadioGroupUncheckBehavior() {
      const lastRadioGroupValues = new WeakMap;
    
      function handleRadioGroupUncheck({ target }) {
        target = target.closest('[type="radio"]');
    
        if (target) {
          const nodeList = target.form.elements[target.name];
    
          if (
            lastRadioGroupValues.get(nodeList) !== nodeList.value
          ) {
            lastRadioGroupValues.set(nodeList, nodeList.value);
          } else {
            lastRadioGroupValues.delete(nodeList);
    
            target.checked = false;
          }
        }
      }
      document
        .querySelectorAll('form')
        .forEach(elm => {
          elm.addEventListener('click', handleRadioGroupUncheck)
        });
    }
    
    enableRadioGroupUncheckBehavior();
    body { margin: 0; }
    fieldset {
      margin: 0 0 8px 0;
      padding: 8px 4px 4px 4px;
    }
    [type="radio"] {
      position: relative;
      display: inline-block;
      width: 5em;
      margin: 1.4em 0 0 0;
    }
    [type="radio"]:before {
      position: absolute;
      top: -1.4em;
      left: .3em;
      display: inline-block;
      width: 100%;
      height: 100%;
      content: attr(value);
    }
    <form>
      <fieldset>
        <legend>Chapters of Podcast A (unchecking a chapter is enabled)</legend>
    
        <input type="radio" name="podcast-a-chapter" value="Chapter 1" />
        <input type="radio" name="podcast-a-chapter" value="Chapter 2" />
        <input type="radio" name="podcast-a-chapter" value="Chapter 3" />
        <input type="radio" name="podcast-a-chapter" value="Chapter 4" />
        <input type="radio" name="podcast-a-chapter" value="Chapter 5" />
        <input type="radio" name="podcast-a-chapter" value="Chapter 6" />
        <input type="radio" name="podcast-a-chapter" value="Chapter 7" />
        <input type="radio" name="podcast-a-chapter" value="Chapter 8" />
        <input type="radio" name="podcast-a-chapter" value="Chapter 9" />
    
      </fieldset>
      <fieldset>
        <legend>Chapters of Book B (unchecking a chapter is enabled)</legend>
    
        <input type="radio" name="book-b-chapter" value="Chapter 1" />
        <input type="radio" name="book-b-chapter" value="Chapter 2" />
        <input type="radio" name="book-b-chapter" value="Chapter 3" />
        <input type="radio" name="book-b-chapter" value="Chapter 4" />
        <input type="radio" name="book-b-chapter" value="Chapter 5" />
        <input type="radio" name="book-b-chapter" value="Chapter 6" />
        <input type="radio" name="book-b-chapter" value="Chapter 7" />
        <input type="radio" name="book-b-chapter" value="Chapter 8" />
        <input type="radio" name="book-b-chapter" value="Chapter 9" />
        <input type="radio" name="book-b-chapter" value="Chapter 10" />
        <input type="radio" name="book-b-chapter" value="Chapter 11" />
        <input type="radio" name="book-b-chapter" value="Chapter 12" />
        <input type="radio" name="book-b-chapter" value="Chapter 13" />
    
      </fieldset>
    </form>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search