{ jQuery Events. }

Objectives:

By the end of this chapter, you should be able to:

  • Explain what event delegation is
  • Compare and contrast preventDefault and stopPropagation

Event Delegation

Event delegation is a very commonly used feature of jQuery. But what is it? From learn.jQuery.com:

Event delegation refers to the process of using event propagation (bubbling) to handle events at a higher level in the DOM than the element on which the event originated. It allows us to attach a single event listener for elements that exist now or in the future.

Let's revisit the following HTML, and include jQuery:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <ul> Ingredients
        <li>Sugar</li>
        <li>Milk</li>
        <li>Eggs</li>
        <li>Flour</li>
        <li>Baking Soda</li>
    </ul>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.js"></script>
</body>
</html>

What we would like to do is console.log the text of an li when the user clicks on it. Moreover, we'd like to do this by adding a single event listener on the ul instead of one for each li. We did something very similar to this when we learned about the DOM with vanilla JavaScript. So what does it look like in jQuery? We still use the on method, but with one small addition:

$(function(){
    // pay CLOSE attention to the 2nd parameter
    $("ul").on("click", "li", function(e){
        console.log("You just clicked on ", $(e.target).text());
    });
});

In this case, you can also refer to the event target using the keyword this:

// an equivalent approach:
$(function(){
    // pay CLOSE attention to the 2nd parameter
    $("ul").on("click", "li", function(){
        console.log("You just clicked on ", $(this).text());
    });
});

The big difference here is that our on method is now accepting three arguments, not two. With event delegation, the callback for the event gets passed as the third parameter. The second parameter is a CSS selector which acts as a filter: the callback only executes if the event target matches the selector passed in.

This is quite useful for adding event listeners that you want to trigger on that don't yet exist on the page. Let's see this in action. Create a new empty HTML file, throw the following code into it, and open the page in Chrome:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <button>Click me to make a new div!</button>
  <div id="container"></div>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <script>
    $(function(){
      var count = 0;
      $("button").on("click", function(){
        var $newDiv = $("<div>", {
          text: "div number " + count
        });
        count++;
        $("#container").append($newDiv);
      });
      $("#container").on("click", "div", function(e){
         console.log("You just clicked on ", $(e.target).text());
      });
    });
  </script>
</body>
</html>

In this example, the container is delegating the click event to the child div elements that don't exist when the page loads. You can read more about event delegation here and here

preventDefault vs stopPropagation

With vanilla JavaScript, we saw that the event object contains a preventDefault method to stop the default behavior of an event. This is very common with form submissions because the default action of a form is to refresh a page. Using preventDefault is a very common way of performing validation as well, by making sure that we disable all default behavior until certain conditions have been met.

There's another method, called stopPropagation, which is sometimes confused with preventDefault. Let's briefly highlight an example to show the difference between the two. These methods both exist in vanilla JS and jQuery so you can use them in both environments.

Create a new HTML file, put the following code into it, then open the page in Chrome and open your dev tools (for simplicity, we've thrown the relevant JavaScript code inside of a script tag):

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Long list</title>
</head>
<body>
  <div>
    <a href="http://www.google.com" id="google">Google</a>
  </div>
  <div>
    <a href="http://www.yahoo.com" id="yahoo">Yahoo</a>
  </div>
  <div>
    <a href="http://www.bing.com" id="bing">Bing</a>
  </div>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <script>
    $(function() {

      $("div").on('click', function(e) {
        console.log("you clicked on a div!");
      });

      $("#google").on('click', function(e) {
        e.preventDefault();
      });

      $("#yahoo").on('click', function(e) {
        e.preventDefault();
        e.stopPropagation();
      });

      $("#bing").on('click', function(e) {
        e.stopPropagation();
      });

    });
  </script>
</body>
</html>

As you can see, this page consists of three a tags, each of which is inside of a div. There are listeners on each a tag, and on each div, so that some code should execute whenever you click on a link or on a div.

However, the behavior you see should be slightly different depending on which link you click on:

  • If you click on "Google," you should see that the link doesn't do anything, but you get a message logged to the console. e.preventDefault() is preventing the default behavior of the link (i.e., taking you to Google.com), but it doesn't affect the event listener on the parent div.
  • If you click on "Yahoo," nothing should happen. The link is broken, as with "Google," but you also shouldn't see anything in the console! This is because e.stopPropagation() stops the click event from bubbling up from the a tag and on to the link.
  • If you click on "Bing", you'll see that the link works. e.stopPropagation() doesn't prevent the default behavior of the link, it just stops the event from bubbling up to the parent div.

Just remember: stopPropagation will prevent an event from bubbling up, but it won't impact the event's behavior on the target. If you want to stop the default behavior of the event on its target, use preventDefault. This will begin to make more sense once you start building full-stack web applications, and begin using these methods (especially preventDefault) more regularly.

If you want to learn more about the difference between stopPropagation and preventDefault, you can read about it here.

When you're ready, move on to jQuery Best Practices

Continue