Skip to content
Advertisement

Changed data attribute not recognized in jquery selector

I’ve the following html structure

<body data-page="first">
   <div class="start">Test</div>
</body>

and the following js

$('body[data-page="first"] .start').on('click',function (){
    body.attr('data-page','second');
});
$('body[data-page="second"] .start').on('click',function (){
    console.log('Test');
});

I would expect, that after the second click on .start, the console would show “Test”, but it doesn’t…

Can you tell me what I’m doing wrong?

Thanks in advance!

Advertisement

Answer

While you have your answer, I don’t think the essential point has been made in any of the answers so far, and that is that the binding of an event handler must happen after the target element exists.

When you try to bind an event handler to a particular element in the DOM, the element must exist at the time. If it does not exist, the handler has nothing to bind to, and so the binding fails. If you later create the element, it’s too late, unless you re-run the binding statement.

It will soon become second nature to call appropriate event handler binding statements after you create a new element (by modifying the HTML using javascript) that needs a handler.

For instance, in my current project I regularly make AJAX calls to a server to replace blocks of HTML as things happen on the page. Even if some of the new elements are exactly the same as the ones being replaced, they will not inherit any bindings from the replaced elements. Whenever I update the HTML I call a function that contains necessary statements to bind my event handlers to the new copy of the active elements.

Your code would work if you made the following change:

$('body[data-page="first"] .start').on('click',function ()
{
    body.attr('data-page','second');
    $('body[data-page="second"] .start').on('click',function (){
        console.log('Test');
    });
})

A couple of other (off-topic, but related) points:

  • It’s possible to bind a handler to an element multiple times. The trick to avoiding this is to include the .off() method in the chain before binding (noting though that .off(“click”) will unbind all click handlers bound to that element, not just yours) e.g.

    $(“#mybutton”).off(“click”).click(function(){myHandler()});

  • “the arrow function doesn’t have its own ‘this’ value” () so don’t use arrow functions in event handlers if you plan to reference any of the element’s properties via ‘this’. e.g.

    $(“#mybutton”).off(“click”).click(() => {console.log(${this.id})}); // >> “undefined”

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement