DEV Community

loading...
Cover image for JavaScript-30-Day-10

JavaScript-30-Day-10

cenacr007_harsh profile image KUMAR HARSH ・4 min read

Hold Shift And Check Checkboxes

Demo

ss.png

Before we begin today's Blog I would like to Thank You everyone who is consistently reading my Blog and supporting me. This is my 10th day on dev.to and my 10th blog as well and the support I have received is something I never even Imagined. Once again a big Thank You to everyone reading this blog.

Today we worked on something very useful, a common layout you would see in an email client.

When a user clicks a checkbox, holds Shift, and then clicks another checkbox a few rows down, all the checkboxes in between those two checkboxes should be checked.

By default some checkboxes were provided and due to this code in CSS we can check any box and the text had a line-through.

input:checked + p {
        background: #f9f9f9;
        text-decoration: line-through;
      }
Enter fullscreen mode Exit fullscreen mode

So the very first thing we did was to select all checkboxes where I Learned how to select the elements by the type key.

const checkboxes = document.querySelectorAll(
        '.inbox input[type="checkbox"]'
      );
Enter fullscreen mode Exit fullscreen mode

Now that we have a NodeList of all the checkboxes we will loop through every single one using forEach()and add eventListeners().

checkboxes.forEach((checkbox) =>
        checkbox.addEventListener("click", handleCheck)
      );
Enter fullscreen mode Exit fullscreen mode

One thing to note here is that we use the click event instead of change event, because click event will fire even if we use the keyboard.

Now we will write our logic inside the handleCheck function, which will be called as soon as the user clicks any of the boxes.

Next thing we need to take care of is, when we check the first box, we need to put that into a variable, because when we check our second one (while holding down shift) we need to know what the last one was. So we'll create a variable to maintain a reference to it, and after creating the variable we'll update it at the end of the handleCheck function.

let lastChecked;
function handleCheck(e) {
//rest of the code
lastChecked = this;
Enter fullscreen mode Exit fullscreen mode

Note: We use let instead of const because this variable is going to update constantly.

Now we need to figure out what checkboxes we need to check based on the checkboxes the user clicks. So rather than trying to find where in the DOM they are and trying to figure out like which elements are in-between and finding it's parents.......
This is vary fragile way to do so because we are dependent on the HTML set and if someone else comes along and changes the HTML a little bit, the code would just break and we do not want that.

What we are going to do instead is we are going to loop over every single checkbox and we are going to create a variable called inBetween (set to false initially) and what inBetween will do is we'll loop over the entire NodeList of checkboxes and as soon as we find a checked checkbox we'll it's value to true and the loop will go one and the second time we find the checked element we'll set if back to false again.

Now before we code the logic for inBetweeen we need to perform another check, first if the shift if pressed down and secondly while clicking the checkbox, user is checking it and not unchecking it because the click event gets fired on both occasions.

let inBetween = false;
        if (e.shiftKey && this.checked) {
          //loop over every single checkbox
          checkboxes.forEach((checkbox) => {
            if (checkbox === this || checkbox === lastChecked) {
              inBetween = !inBetween;
            }
            if (inBetween) {
              checkbox.checked = true;
            }
          });
        }
Enter fullscreen mode Exit fullscreen mode

This (e.shiftKey && this.checked) ensures that we do not loop over the checkboxes unless shift is pressed and the click was checking and not unchecking.

Using this part we loop over every single checkbox and update inBetween accordingly.

checkboxes.forEach((checkbox) => {
            if (checkbox === this || checkbox === lastChecked) {
              inBetween = !inBetween;
            }
Enter fullscreen mode Exit fullscreen mode

We have used this:

if (checkbox === this || checkbox === lastChecked) {
              inBetween = !inBetween;
            }
Enter fullscreen mode Exit fullscreen mode

instead of simply setting to true or false so that our checkboxes work both ways so we do inBetween is opposite of itself.

NOTE: keep in mind checks are always performed top->bottom.

First case is where user clicks a lower checkbox first and then clicks upper checkbox in which case checkbox === this is true (here this is equal to the one that got checked) and since this checkbox is the one we are currently looping over so condition is true.

Seconnd case is where, first the user clicks a upper box and then clicks a box below it. In this case checkbox === lastChecked is true as the upper box is kept in lastChecked variable and the lower box is the currently checked box, so we revert the value of inBetween using inBetween = !inBetween that is set it to true.

Long story short, it will start checking from top and as soon as checked box is found inBetween is set to true and second time a checked box is found inBetween is set to false again.

Making use of inBetween flag this checks all boxes while inBetween is true that all the boxes in between

if (inBetween) {
              checkbox.checked = true;
            }
Enter fullscreen mode Exit fullscreen mode

This is the complete JavaScript code:

const checkboxes = document.querySelectorAll(
        '.inbox input[type="checkbox"]'
      );

      let lastChecked;
      function handleCheck(e) {
        //we need to check if they had the shift key down
        //and check that they are checking it not unchecking it
        let inBetween = false;
        if (e.shiftKey && this.checked) {
          //loop over every single checkbox
          checkboxes.forEach((checkbox) => {
            if (checkbox === this || checkbox === lastChecked) {
              inBetween = !inBetween;
            }
            if (inBetween) {
              checkbox.checked = true;
            }
          });
        }
        lastChecked = this;
      }

      checkboxes.forEach((checkbox) =>
        checkbox.addEventListener("click", handleCheck)
      );
Enter fullscreen mode Exit fullscreen mode

and with this our project for the day was completed.

GitHub repo:

Blog on Day-9 of javascript30

Blog on Day-8 of javascript30

Blog on Day-7 of javascript30

Follow me on Twitter
Follow me on Linkedin

DEV Profile

cenacr007_harsh image

You can also do the challenge at javascript30

Thanks @wesbos , WesBos to share this with us! 😊💖

Please comment and let me know your views

Thank You!

Discussion (2)

Collapse
rash123 profile image
Collapse
cenacr007_harsh profile image
Forem Open with the Forem app