Lieutenant Dan
Lieutenant Dan

Reputation: 8274

'select all' checkbox on dynamic HTML checkboxes

I have content being iterated, and then outputted to HTML, from javascript obj data. I am trying to incorporate a check box, that when clicked; will 'select all' or 'check all' of my other checkboxes (these other checkboxes are coming from my JavaScript code, from iterated for loop).

attempt:

function checkAll(checkId){
    var inputs = document.getElementsByTagName("input");
    for (var i = 0; i < inputs.length; i++) { 
        if (inputs[i].type == "checkbox" && inputs[i].id == checkId) { 
            if(inputs[i].checked == true) {
                inputs[i].checked = false ;
            } else if (inputs[i].checked == false ) {
                inputs[i].checked = true ;
            }
        }  
    }  
}

JS obj data to the HTML content:

var json =[{
            "Name": "zips",
            "Type": "Directory",
            "DateModified": "6/14/2018 17:22:50",
            "Size": "5 KB",
        }, {
            "Name": "presets",
            "Type": "Directory",
            "DateModified": "5/11/2018 7:32:10",
            "Size": "2 KB",
        }, {
            "Name": "workflow",
            "Type": "Directory",
            "DateModified": "6/26/2018 10:29:59",
            "Size": "6 KB",
        },{
            "Name": "software",
            "Type": "Directory",
            "DateModified": "3/16/2018 10:29:59",
            "Size": "16 KB",
        },{
            "Name": "mmm_data",
            "Type": "Directory",
            "DateModified": "6/27/2018 1:19:29",
            "Size": "3 KB",
        },{
            "Name": "jobs",
            "Type": "Directory",
            "DateModified": "4/27/2018 11:59:59",
            "Size": "3 KB",
        },
];

var string ="";

for (i in json) {
    string +='<div class="row"><div class="col-md-15 col-sm-1"><input type="checkbox" name="chk[]"></div><div class="col-md-15 col-sm-4"><span class="folders">'+json[i].Name+'</span></div><div class="col-md-15 col-sm-3"><span class="directory">'+json[i].Type+'</span></div><div class="col-md-15 col-sm-3"><span class="date-stamp">'+json[i].DateModified+'</span></div><div class="col-md-15 col-sm-1"><span class="date-size">'+json[i].Size+'</span></div></div>';
};
document.getElementsByClassName('update-data')[0].innerHTML =string

static HTML:

<div class="data-columns">
    <div class="row" id="hd">
        <div class="col-md-15 col-sm-1">
            <input type="checkbox" onclick="checkAll('chk');" >    
        </div>
      <div class="col-md-15 col-sm-4">
        <div id="named" class="sr">Name</div>
        </div>
      <div class="col-md-15 col-sm-3">
        <div id="type" class="sr">Type</div>
        </div>
      <div class="col-md-15 col-sm-3">
          <span id="dated" class="sr">Date Modified</span>
        </div>

      <div class="col-md-15 col-sm-1">
        <span id="size" class="sr">Size</span>
        </div>
    </div>   

    <div class="update-data">

    </div>

</div>

enter image description here

Upvotes: 1

Views: 6678

Answers (3)

brandonmack
brandonmack

Reputation: 178

In your code, you are using inputs[i].id == checkId to filter your checkboxes. This means only checkboxes with the ID passed in will toggle. However, element ID's must be unique, so this isn't going to work.

Here's what I would do: use a class such as toggleable that tells your script the box should be changed. You then check for that class on each checkbox when toggling them. Your modified code would look like this:

function checkAll(checkClass){
    var inputs = document.getElementsByTagName("input");
    for (var i = 0; i < inputs.length; i++) { 
        if (inputs[i].type == "checkbox" && inputs[i].classList.contains(checkClass)) { 
            if(inputs[i].checked == true) {
                inputs[i].checked = false ;
            } else if (inputs[i].checked == false ) {
                inputs[i].checked = true ;
            }
        }  
    }  
}

You then just need to add the same class to any boxes you want to have be effected, and pass that class name in to your function in place of an id.

Upvotes: 1

Guillaume Georges
Guillaume Georges

Reputation: 4020

There's a few issues in your code :

  • your first checkbox doesn't have the 'chk' id. I suppose it should.
  • you're passing the id of the checkbox and then comparing every checkbox's id to this id. And neither of the other checkboxes have an id. So, you're not checking / unchecking anything else but the checkbox you clicked.
  • you're checking the first checkbox, but then the default action of the click event occurs. And the first checkbox is unchecked.

So, while trying to maintain your logic and existing code, I fixed it by :

  • removing the inputs[i].id == checkId condition in your if
  • adding the 'chk' id to the first checkbox
  • not checking / unchecking the first checkbox. Leave that to the default behaviour of the click event. To do this, add an if to not check / uncheck the 'chk' checkbox.

Full snippet, except styling :

function checkAll(checkId) {
  var inputs = document.getElementsByTagName("input");
  for (var i = 0; i < inputs.length; i++) {
    if (inputs[i].id != checkId) {
      if (inputs[i].type == "checkbox") {
        if (inputs[i].checked == true) {
          inputs[i].checked = false;
        } else if (inputs[i].checked == false) {
          inputs[i].checked = true;
        }
      }
    }
  }
}

var json = [{
  "Name": "zips",
  "Type": "Directory",
  "DateModified": "6/14/2018 17:22:50",
  "Size": "5 KB",
}, {
  "Name": "presets",
  "Type": "Directory",
  "DateModified": "5/11/2018 7:32:10",
  "Size": "2 KB",
}, {
  "Name": "workflow",
  "Type": "Directory",
  "DateModified": "6/26/2018 10:29:59",
  "Size": "6 KB",
}, {
  "Name": "software",
  "Type": "Directory",
  "DateModified": "3/16/2018 10:29:59",
  "Size": "16 KB",
}, {
  "Name": "mmm_data",
  "Type": "Directory",
  "DateModified": "6/27/2018 1:19:29",
  "Size": "3 KB",
}, {
  "Name": "jobs",
  "Type": "Directory",
  "DateModified": "4/27/2018 11:59:59",
  "Size": "3 KB",
}, ];

var string = "";

for (i in json) {
  string += '<div class="row"><div class="col-md-15 col-sm-1"><input type="checkbox" name="chk[]"></div><div class="col-md-15 col-sm-4"><span class="folders">' + json[i].Name + '</span></div><div class="col-md-15 col-sm-3"><span class="directory">' + json[i].Type + '</span></div><div class="col-md-15 col-sm-3"><span class="date-stamp">' + json[i].DateModified + '</span></div><div class="col-md-15 col-sm-1"><span class="date-size">' + json[i].Size + '</span></div></div>';
};
document.getElementsByClassName('update-data')[0].innerHTML = string;
<div class="data-columns">
  <div class="row" id="hd">
    <div class="col-md-15 col-sm-1">
      <input type="checkbox" id="chk" onclick="checkAll('chk')" ;>
    </div>
    <div class="col-md-15 col-sm-4">
      <div id="named" class="sr">Name</div>
    </div>
    <div class="col-md-15 col-sm-3">
      <div id="type" class="sr">Type</div>
    </div>
    <div class="col-md-15 col-sm-3">
      <span id="dated" class="sr">Date Modified</span>
    </div>

    <div class="col-md-15 col-sm-1">
      <span id="size" class="sr">Size</span>
    </div>
  </div>

  <div class="update-data">

  </div>

</div>

Upvotes: 1

Anthony
Anthony

Reputation: 239

Your iteration looks mostly good. However, part of your conditional checks that the input has a specific id. Id's are unique, so at most this could only reach one input. If you remove that part you should be good. Also, this will be buggy if the user has selected one or more boxes before selecting the select all button because all this function does is flip them, so whatever ones they have already checked will be unchecked. I'd do something along the lines of:

function checkAll(checked){ // pass true or false to check or uncheck all
    var inputs = document.getElementsByTagName("input");
    for (var i = 0; i < inputs.length; i++) { 
        if (inputs[i].type == "checkbox") { 
            inputs[i].checked = checked; 
            // This way it won't flip flop them and will set them all to the same value which is passed into the function
        }  
    }  
}

In summary, your big issue is that you are checking the id in the conditional, and only one element on the page can have that id.

Upvotes: 5

Related Questions