Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JQuery selector still working after I remove the class?

I have two jquery functions that work together, one depends on a class, another removes the class.

Once it is removed I would expect the functionality to stop working, but it carries on?

Whats going on?

Here is the fiddle, try it out for yourself.

<div class="container disabled"> 
    <a href="www.google.com">Go to Google</a>
</div>
<label>
    <input type="checkbox" />Enable link</label>

The JS

$('.disabled > a').click(function (e) {
    e.preventDefault();
    e.stopPropagation();
    alert('should stop working');
});

$('input[type=checkbox]').change(function () {
    $('.container').removeClass('disabled');
});
like image 279
shenku Avatar asked Mar 06 '14 22:03

shenku


3 Answers

It looks like you want to be using delegated event handlers rather than static event handlers. Let me explain.

When you run a line of code like this:

$('.disabled > a').click(function (e) {

this installs an event handler on any objects that match the selector at that moment in time. Those event handlers are then in place forever. They no longer look at what classes any elements have. So changing a class after you install a static event handler does not affect which elements have event handlers on them.

If you want dynanamic behavior where which elements respond to an event does depend upon what classes are present at any given moment, then you need to use delegated event handling.

With delegated event handling, you attach the event "permanently" to a parent and then the parent evaluates whether the child where the event originated matches the select each time the event fires. If the child no longer matches the select, then the event handler will not be triggered. If it does, then it will and you can add/remove a class to cause it to change behavior.

The general form of delegated event handlers are like this:

$("#staticParent").on("click", ".childSelector", fn);

You ideally want to select a parent that is as close to the child as possible, but is not dynamic itself. In your particular example, you don't show a parent other than the body object so you could use this:

$(document.body).on("click", ".disabled > a", function() {
    e.preventDefault();
    e.stopPropagation();
    alert('should stop working');    
});

This code will then respond dynamically when you add remove the disabled class. If the disabled class is present, the event handler will fire. If it is not present, the event handler will not fire.

Working demo: http://jsfiddle.net/jfriend00/pZeSA/

Other references on delegated event handling:

jQuery .live() vs .on() method for adding a click event after loading dynamic html

jQuery .on does not work but .live does

Should all jquery events be bound to $(document)?

JQuery Event Handlers - What's the "Best" method

jQuery selector doesn't update after dynamically adding new elements

like image 142
jfriend00 Avatar answered Oct 12 '22 10:10

jfriend00


Changing the class after the event handler is bound has absolutely no effect as the event handler is not suddenly unbound, it's still bound to the same element.

You have to check for the class inside the event handler

$('.container > a').click(function (e) {
    if ( $(this).closest('.container').hasClass('disabled') ) {
        e.preventDefault();
        e.stopPropagation();
    }
});

$('input[type=checkbox]').change(function () {
    $('.container').toggleClass('disabled', !this.checked);
});

FIDDLE

like image 45
adeneo Avatar answered Oct 12 '22 10:10

adeneo


When the selector runs, it gets a list of elements including the one in question and adds a click event handler to it.

Then you remove the class - so any subsequent jQuery selectors wouldn't get your element - but you have already attached the event so it will still fire.

The selector you have used runs on the line you declared it - it isn't lazily initialized when clicks happen.

like image 30
Fenton Avatar answered Oct 12 '22 11:10

Fenton