Check all: A JavaScript pattern to check a group of checkboxes

It has been too long since I wrote about my JavaScript learning journey, so I'm excited to have a new pattern to add to my toolkit. The check all pattern allows a user to check or uncheck a group of checkboxes (or radio boxes) by checking a single box that controls the rest of the group, like this:

The code including HTML is available on Codepen. Here's how I wrote the JavaScript:

1: Create the object

//create an object called checkAll
    var CheckAll = function(rootElement) {}

Whatever ends up inside the curly braces of this object will form the blueprint for every object called CheckAll. The value inside the parenthesis represents what will be parsed into the function. This word can be anything at all.

2. Create a new instance of the object for each element with the class .js_CheckAll

//get all instances of checkAll on the page
    var checkAlls = doc.querySelectorAll('.js_CheckAll');
    //store total number of checkAll on the page
    var checkAllsTotal = checkAlls.length;
    //variable to store one of the checkAll
    var checkAll;
    //create a counter for the loop
    var i;
    //loop through each check-all group
    for ( i = 0; i < checkAllsTotal; i = i + 1 ) {
        //create a new object for each checkAll group
        checkAll = new CheckAll(checkAlls[i]);
        //start init
        checkAll.init();
    }

I have used a loop to find every instance of .js_CheckAll and create a new object for it. Without this approach, only the first .js_CheckAll item on the page will function, which isn't very useful to me. Taking this approach means that this pattern can be re-used as many times as I want it to on the same page. Even if I only wanted to use this pattern once on each page (for now), this may change in the future. As much as possible, I want my code can to stand the test of time and afford flexibility.

The above code is the scaffolding for this pattern. I can get all instances of .js_CheckAll and I can create new objects for them, but now I need to make the objects do something; they need some properties and methods.

3. Set variables and values

Inside the object (in step 1), I have stored values in variables so they can be re-used throughout the code. So, if I need to change a value later on in my project, I will only need to do it in one place.

//create a variable for the markup container
var markupContainer;
//create a variable and store the class for the container of the checkAll markup
var markupContainerSelector = '.js_CheckAll-container';
//create a property and store the markup for the checkAll input
var checkAllMarkup = '<label for="check-all" class="FormUnit-label"><input class="js_Check-all" type="checkbox" name="check-all" id="check-all">All</label>';
//create a variable and store the check-all input class
var checkAllSelector = '.js_Check-all';
//create a variable to store selector for all checkboxes
var allCheckboxesSelector = '.js_CheckAll-checkbox';
//create a variable to store the markup
var markup;
//create a variable to store the checkAll button
var checkAllButton;
//create variable for all other checkboxes
var allCheckboxes;
//create a variable for one checkbox
var checkbox;

The check all button

The check all button is not in the markup. I have used JavaScript to add it because this functionality is an enhancement that can be used by browsers that support JavaScript. If it isn't usable by some users (even if it's only a small number), it doesn't make sense to show a checkbox that can't be used.

4. Create an initialisation method

//create an init function
this.init = function() {
      //get the markup of the checkbox container
      markupContainer = rootElement.querySelector(markupContainerSelector);
      //store the innerHTML of the markup container
      markup = markupContainer.innerHTML;
      //add the markup of the checkbox
      markup += checkAllMarkup;
      //update container with the new markup
      markupContainer.innerHTML = markup;
      //get the checkAll input
      checkAllButton = markupContainer.querySelector(checkAllSelector);
      //add an event listener to the checkAll button
      checkAllButton.addEventListener('click', All, false);
 };

The select all button is created and an event listener is added, which calls a function every time the box is selected.

5. Check all functionality

The event listener added to the check all button will invoke this function.

//create a function to select all of the checkboxes
var All = function(ev) {
   //store all checkboxes
   allCheckboxes = rootElement.querySelectorAll(allCheckboxesSelector);
   //store the length of the checkboxes array
   var total = allCheckboxes.length;
   //set a counter for the loop
   var i;
   //if this is checked
   if (this.checked) {
   	//loop through each checkbox
   	for ( i = 0; i < total; i = i + 1 ) {
     	checkbox = allCheckboxes[i];
    	//check each checkbox
        checkbox.checked = true;
    }
    } else {
      for ( i = 0; i < total; i = i + 1 ) {
         checkbox = allCheckboxes[i];
    	 //uncheck each checkbox
         checkbox.checked = false;
      }
    }
 };

A few months ago, I wrote about a JavaScript number input spinner I created using a similar approach to this. That post goes into more detail because I learnt a lot from building it. I used those lessons to build this pattern and I was surprised at how quickly I could make this work. That's one of the great benefits of documenting learnings.