Skip to content
Advertisement

Javascript function called only once despite multiple event listeners

I am rebuilding one of my own websites specifically to avoid using jQuery since I used so little of it that the memory overhead just isn’t necessary, and I’m not concerned about supporting older browsers (the version of Firefox I’m using is likely to be the oldest browser to ever look at my sites; so if they work in that they’ll work for 99.99% of my audience). I am encountering a problem when adding multiple event listeners to a few list items in the document.

HTML snippet:

<div class="SubColumn LeftCol grid_12 alpha">
    <div class="InfoBox grid_12 alpha omega">
        <h1>Side Detail</h1>
        <ul>
            <li data-detail-item="Detail item" data-detail-info="Info about the detail item!">Detail item</li>
            <li data-detail-item="Detail item 2" data-detail-info="Info about the second detail item!">Detail item 2</li>
            <li>Detail item</li>
            <li>Detail item</li>
            <ul>
                <li>Detail item</li>
                <li>Detail item</li>
                <li>Detail item</li>
                <li>Detail item</li>
            </ul>
            <li>Detail item</li>
            <li>Detail item</li>
            <li>Detail item</li>
            <li>Detail item</li>
        </ul>
    </div>
</div>

Relevant Javascript:

function PrepareDefBoxes()
{
    // I'm using document.querySelectorAll() here as a generic swiss army knife
    // I use it multiple times throughout the script
    // Quite frankly its CSS-selector-syntax input is easier for me to read & maintain
    // CSS-style selectors even work on the custom data-* global attributes ^_^
    var AllDeets = document.querySelectorAll("li[data-detail-item][data-detail-info]");
    // An array of events to add to all the details list items
    // Declared here because I *might* need to add more events; you never know~
    var Events = ["mouseover", "mouseout", "click"];

    // This is a coding trick I've used in C++ and in php
    // If you have nested for loops and all your code is in the innermost loop,
    // you can actually put them all on the same line or on successive lines,
    // then have the scoping braces following the innermost for loop :3
    for(var i = 0; i < AllDeets.length; i++)
    for(var e = 0; e < Events.length; e++)
    {
        AllDeets[i].addEventListener( Events[e], function(event) {
            DefBox(event.target);
        });
        console.log("Added " + Events[e] + " to " + AllDeets[i].innerHTML);
    }
}

function DefBox(ListItem)
{
    console.log("It works!");
}

The function PrepareDefBoxes() is called by an earlier Bootstrap() function that is itself invoked via an onload inline event listener on the document’s body tag a la <body onload="Bootstrap()">. When I refresh the page, I get this chunk of output logged to the console, exactly as expected:

Added mouseover to Detail item
Added mouseout to Detail item
Added click to Detail item
Added mouseover to Detail item 2
Added mouseout to Detail item 2
Added click to Detail item 2

However, when I randomly mouse over and mouse out from the two list items that should have THREE event listeners bound to each of them, the function DefBox() is only ever called once! And it logs its output to the console only that once. I don’t even get extra output by clicking on the list items, either. When I move the cursor around over those two items, I should be getting a mess of “It works!” printed to the console.

I humbly request solutions that do not use jQuery, por favor!

Advertisement

Answer

Your code works fine. I would guess that you just misinterpreted the console output information.

See fiddle: https://jsfiddle.net/3h4y0t01/1/ (I’ve just made output more obvious):

var counter = 0;
function DefBox(ListItem)
{
    document.getElementById('out').innerHTML = counter++;
}
Advertisement