user2899508
user2899508

Reputation: 15

JavaScript event delegation not working as expected

I just thought I could use event delegation on ul element so that a click on any of the li elements will bubble up to ul. This is then captures by ul's event.target to get the right li element and proceed according to what I need with the li. This is the way I learnt. But clicking on the contact li element is not alerting as expected. Please help me with this. My company forces me to use event delegation. That's why this is so important.

HTML

<!doctype html>
<html>
<head>
<title>Title</title>
<link rel="stylesheet" type="text/css" href="style.css" >
<script src="JavaScript.js"></script>
</head>
<body>
<div>
<ul id="nav">
            <li id="click"><a href="#">Contact</a></li>
            <li> <a href="#">Blog</a></li>
            <li> <a href="#">Work</a></li>
            <li> <a href="#">About</a></li>
            <li> <a href="#">Home</a></li>
</ul>
</div>
</body>
</html>

JS

var list = document.getElementById("nav");
list.addEventListener("click", function(event) {
switch(event.target.id) {
case "click":
alert("haha");
break;
}, false);

CSS

body {
margin: 0;
}
#nav {
    list-style-type: none;
    margin: 0;
    padding: 0;
}
#nav li {
    width: 20%;
    float: left;
    text-align: center;
    display: inline;
}
#nav li a {
line-height: 40px;
    display: block;
    padding: 0.5em 5px;
    text-decoration: none;
    font-weight: bold;
    color: #F2F2F2;
    -webkit-box-shadow: 3px 3px 3px rgba(51,51,51,0.3);
    box-shadow: 3px 3px 3px rgba(51,51,51,0.3);
}
#nav a:link, #nav a:visited {
    background-color: #071726;
}
#nav a:hover, #nav a:active, #nav a:focus {
    background-color: #326773;
}

Upvotes: 0

Views: 545

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074038

Your main problem is that there's a syntax error in your event handler, you're missing the } for the switch. (Using consistent indentation will help avoid those kinds of errors.)

Then your problem is that event.target isn't what you think it is. event.target is the actual element that was clicked. The odds in your case are that the actual element that was clicked is the a element (the link).

So what you want to do is look at the lineage from the clicked element down to the element on which you hooked the click (which will be this), looking for the one that's at the level you want (in your case, an li): Live Example | Source

var list = document.getElementById("nav");
list.addEventListener("click", function(event) {
    // Start with the element that was clicked
    var li = event.target;

    // You may want `event.preventDefault();` here

    // If the element exists, it isn't the list on which we hooked
    // the event, and its tag name isn't LI, go to the parent
    // element instead.
    while (li && li !== this && li.tagName.toUpperCase() !== "LI") {
        li = li.parentNode;
    }

    // If we got an LI, use it
    if (li) {
        // OR you may want `event.preventDefault();` here
        switch(li.id) {
            case "click":
                alert("haha");
                // OR you may want `event.preventDefault();` here
                break;
        }
    }
}, false);

Also, be sure that the code above is either in a script element below your navigation list in the HTML, or in an onload handler (I recommend the former, just put the script at the end).

And finally: Since the link's href is just "#", I'm guessing you don't actually want the link to be followed by the browser (as that will scroll up to the top of the page). If that's the case, you'll want to add a call to event.preventDefault() in the handler. I've noted a few places above where you may want it, it depends on whether you always want to prevent the link from being followed, or only in certain cases.


Side note: Although you can, of course, do this work yourself, you can reuse the work of others by using a good library like jQuery, YUI, Closure, or any of several others. For example, in jQuery, that looks like this:

$("#nav").on("click", "li", function(event) {
    // Possibly with `event.preventDefault();` here
    switch (this.id) {
        case "click":
            alert("haha");
            // OR possibly with `event.preventDefault();` here
            break;
    }
});

Other libraries have similar features.

Upvotes: 2

Related Questions