Added event listener for a class, some members of that class unaffected

Issue

I have a grid that will be used as a menu, it consist of a top row made from a ul with 3 li’s set to display:inline-block within each of these li’s there is a ul and under that 4 li’s. I’ve assigned an event listener to respond to click on the li under the inner ul’s with class is "inner".
You can see the code here: http://jsfiddle.net/jimeast123/qK2Ju/2/
When I click on the items in the first 2 columns(you need to avoid clicking on the text) I get the expected alert message when I click on the third column there’s no response. I’ve tried with different numbers of columns and the last column never responds.

My code:
html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>drop down</title>
    <style>
    body {
        margin: 0;
        padding: 0;
    }
    header {
        height: 120px;
        background-color: #eef;
    }
    .top {
        background-color: #fee;
    }
    .top li {
        display: inline-block;
        width: 5.5em;
        height: 1.5em;
        border: 1px solid black;
        text-align: center;
    }
    li {
        list-style: none;
    }
    .inner {
        margin-left: -2.55em;
        display:block;
    }
    li a {
        text-decoration: none;
    }
    .inner li {
        display: block;
        text-align: center;
        background-color: #efe;
    }
    </style>

</head>
<body>
<!-- heading>h1+nav>ul.top>li*5>(a[href=#]>{menu$})>ul.inner>li*4>a[href=#]>{menu$} -->
<header>
    <nav>
        <header>
    <nav>
        <ul class="top">
            <li><a href="#">menuA</a>
                <ul class="inner" id="one">
                    <li><a href="#">item1</a></li>
                    <li><a href="#">item2</a></li>
                    <li><a href="#">item3</a></li>
                    <li><a href="#">item4</a></li>
                </ul>
            </li>
            <li><a href="#">menuB</a>
                <ul class="inner" id="two">
                    <li><a href="#">item1</a></li>
                    <li><a href="#">item2</a></li>
                    <li><a href="#">item3</a></li>
                    <li><a href="#">item4</a></li>
                </ul>
            </li>
            <li><a href="#">menuE</a>
                <ul class="inner" id="five">
                    <li><a href="#">item1</a></li>
                    <li><a href="#">item2</a></li>
                    <li><a href="#">item3</a></li>
                    <li><a href="#">item4</a></li>
                </ul>
            </li>
        </ul>
    </nav>
</header>
    </nav>
</header>
<script src="dropdown.js"></script>
</body>
</html>

JavaScript:

if (document.body.addEventListener) {
    document.body.addEventListener('click', theHandler, false);
} else {
    document.body.attachEvent('onclick', theHandler); //for IE
}

function theHandler(e){
    e = e || window.event;
    var target = e.target || e.srcElement;
    if (target.className.match(/inner/)) {
        //console.log("inner class was clicked");
        alert("inner class was clicked");
    }
}

Solution

The user can’t actually click on the .inner elements because when they try do, what they actually end up clicking on is the child objects in the .inner objects. As such, you won’t get a target with that class.

You have a couple choices. First off, if your HTML isn’t dynamically created with JS code, then you could just apply the event listeners directly to all .inner objects and the normal click event propagation will cause them to trigger when child nodes are clicked on.

Or, if you want to keep the event handler on the body, then the work-around is probably to see if the parent chain contains that class (your target will be several levels below .inner).

function hasClass(elem, cls) {
    var str = " " + elem.className + " ";
    var testCls = " " + cls + " ";
    return(str.indexOf(testCls) != -1) ;
}

function isTargetInClass(target, cls) {
    while (target && target !== document.body) {
        if (hasClass(target, cls)) {
            return true;
        }
        target = target.parentNode;
    }
    return false;
}

function theHandler(e){
    e = e || window.event;
    var target = e.target || e.srcElement;
    if (isTargetInClass(target, "inner")) {
        //console.log("inner class was clicked");
        alert("inner class was clicked");
    }
}

Answered By – jfriend00

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published