33. Handling Events for Multiple Elements


In This Chapter

Learn to efficiently react to multiple events

Revisit how events work for one last time


In its most basic case, an event listener deals with events fired from a single element:

Image

As you build more complicated things, the “one event handler for one element” mapping starts to show its limitation. The most common reason revolves around you creating elements dynamically using JavaScript. These elements you are creating can fire events that you may want to listen and react to, and you can have anywhere from a handful of elements that need eventing support to many MANY elements that need to have their events dealt with.

What you don’t want to do is this:

Image

You don’t want to create an event listener for each element. The reason is because your parents told you so. The other reason is because it is inefficient. Each of these elements carries around data about an event listener and its properties that can really start adding up the memory usage when you have a lot of content. Instead, what you want is a clean and fast way of handling events on multiple elements with minimal duplication and unnecessary things. What you want will look a little bit like this:

Image

All of this may sound a bit crazy, right? Well, in this chapter, you will learn all about how non-crazy this is and how to implement this using just a few lines of JavaScript.

Onwards!

How to Do All of This

Okay - at this point, you know how simple event handling works where you have one element, one event listener, and one event handler. Despite how different the case with multiple elements may seem, by taking advantage of the disruptiveness of events, solving it is actually quite easy.

Imagine we have a case where you want to listen for the click event on any of the sibling elements whose id values are one, two, three, four, and five. Let’s complete our imagination by picturing the DOM as follows:

Image

At the very bottom, we have the elements we want to listen for events on. They all share a common parent with an element whose id value is theDude. To solve our event handling problems, let’s look at a terrible solution followed by a good solution.

A Terrible Solution

Here is what we don’t want to do. We don’t want to have five event listeners for each of these buttons:

var oneElement = document.querySelector("#one");
var twoElement = document.querySelector("#two");
var threeElement = document.querySelector("#three");
var fourElement = document.querySelector("#four");
var fiveElement = document.querySelector("#five");

oneElement.addEventListener("click", doSomething, false);
twoElement.addEventListener("click", doSomething, false);
threeElement.addEventListener("click", doSomething, false);
fourElement.addEventListener("click", doSomething, false);
fiveElement.addEventListener("click", doSomething, false);

function doSomething(e) {
    var clickedItem = e.target.id;
    alert("Hello " + clickedItem);
}

To echo what I mentioned in the intro, the obvious reason is that you don’t want to duplicate code. The other reason is that each of these elements now has their addEventListener property set. This is not a big deal for five elements. It starts to become a big deal when you have dozens or hundreds of elements each taking up a small amount of memory. The other OTHER reason is that your number of elements, depending on how adapative or dynamic your UI really is, can vary. It may not be a nice fixed number of five elements like we have in this contrived example.

A Good Solution

The good solution for this mimics the diagram you saw much earlier where we have just one event listener. I am going to confuse you first by describing how this works. Then I’ll hopefully un-confuse you by showing the code and explaining in detail what exactly is going on. The simple and confusing solution to this is:

1. Create a single event listener on the parent theDude element.

2. When any of the one, two, three, four, or five elements are clicked, rely on the propagation behavior that events possess and intercept them when they hit the parent theDude element.

3. (Optional) Stop the event propagation at the parent element just to avoid having to deal with the event obnoxiously running up and down the DOM tree.

I don’t know about you, but I’m certainly confused after having read those three steps! Let’s start to unconfuse ourselves by starting with a diagram that explains those steps more visually:

Image

The last step in our quest for complete unconfusedness is the code that translates what the diagram and the three steps represent:

var theParent = document.querySelector("#theDude");
theParent.addEventListener("click", doSomething, false);

function doSomething(e) {
    if (e.target !== e.currentTarget) {
        var clickedItem = e.target.id;
        alert("Hello " + clickedItem);
    }
    e.stopPropagation();
}

Take a moment to read and understand the code you see here. It should be pretty self-explanatory after seeing our initial goals and the diagram. We listen for the event on the parent theDude element:

var theParent = document.querySelector("#theDude");
theParent.addEventListener("click", doSomething, false);

There is only one event listener to handle this event, and that lonely creature is called doSomething:

function doSomething(e) {
    if (e.target !== e.currentTarget) {
        var clickedItem = e.target.id;
        alert("Hello " + clickedItem);
    }
    e.stopPropagation();
}

This event listener will get called each time theDude element is clicked along with any children that get clicked as well. We only care about click events relating to the children, and the proper way to ignore clicks on this parent element is to simply avoid running any code if the element the click is from (aka the event target) is the same as the event listener target (aka theDude element):

function doSomething(e) {
    if (e.target !== e.currentTarget) {

        var clickedItem = e.target.id;
        alert("Hello " + clickedItem);
    }
    e.stopPropagation();
}

The target of the event is represented by e.target, and the target element the event listener is attached to is represented by e.currentTarget. By simply checking that these values not be equal, you can ensure that the event handler doesn’t react to events fired from the parent element that you don’t care about.

To stop the event’s propagation, we simply call the stopPropagation method:

function doSomething(e) {
    if (e.target !== e.currentTarget) {
        var clickedItem = e.target.id;
        alert("Hello " + clickedItem);
    }
    e.stopPropagation();

}

Notice that this code is actually outside of my if statement. This is because I want the event to stop traversing the DOM under all situations once it gets overheard.

Putting It All Together

The end result of all of this code running is that you can click on any of the Dude’s children and listen for the event as it propagates up:

Image

Because all of the event arguments are still tied to the source of the event, you can target the clicked element in the event handler despite calling addEventListener on the parent. The main thing to call out about this solution is that it satisfies the problems we set out to avoid. You only created one event listener. It doesn’t matter how many children theDude ends up having. This approach is generic enough to accommodate all of them without any extra modification to your code. This also means that you should do some strict filtering if your theDude element ends up having children besides buttons and other elements that you care about.


Image Tip

Just a quick reminder for those of you reading these words in the print or e-book edition of this book: If you go to www.quepublishing.com and register this book, you can receive free access to an online Web Edition that not only contains the complete text of this book but also features a short, fun interactive quiz to test your understanding of the chapter you just read.

If you’re reading these words in the Web Edition already and want to try your hand at the quiz, then you’re in luck – all you need to do is scroll down!


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.218.226