Click Event Not Working After Class Change

2.6k views Asked by At

I have the following script:

// dashboard maximize
$('#dashboard-actions .btn-maximize').click(function() {

    // max / restore buttons
    $(this).removeClass('btn-maximize').addClass('btn-restore');
    $(this).find('span').removeClass('icon-maximize').addClass('icon-restore');

    // swap tables
    $('#table-dashboard-actions-mini').hide();
    $('#table-dashboard-actions').show();

    // show form
    $('#form-dashboard-actions-btm').show();

    // restyle panel
    $(this).parents('.panel-dashboard').addClass('panel-dashboard-max');

    // animate panel
    $(this).parents('.panel-dashboard').animate({
            width: "100%",
        }, 250, function() {
        // Animation complete.
    });
    $(this).parents('.panel-primary').animate({
            height: "725px"
        }, 250, function() {
        // Animation complete.
    });

});

As you can see, at one point the script changes the class of the clicked button to .btn-restore

However this means that I cannot seem to bind an event to .btn-restore

I originally had this:

// dashboard restore
$('#dashboard-actions .btn-restore').click(function() {

    alert('asdf');
});

And the alert statement didn't work, so I changed it to this:

$('#dashboard-actions .btn-restore').on('click', function() {

But still no joy. Can anyone see what I'm doing wrong?

4

There are 4 answers

0
Tom Jardine-McNamara On BEST ANSWER

As a couple of people have mentioned, event delegation is the key to binding to selectors that don't match yet. The alternative suggestion of binding to the generic selector .button that will always exist and then maintaining the state (maximised or restored) in a variable is also valid.

Your issue with the panel opening and then immediately closing seems to be that you add the .btn-restore class inside the event handler immediately. It shouldn't happen, but it seems like the click event is firing again on the new selector (perhaps something to do with mouseup and mousedown components of the click event?). I'd suggest wrapping your addClass calls within a setTimeout() like so to ensure the classes are changed after any events fire, essentially "pushing" the change to the end of the current execution:

var $btn = $(this);
setTimeout(function () {
    $btn.removeClass('btn-maximize').addClass('btn-restore');
    $btn.find('span').removeClass('icon-maximize').addClass('icon-restore');
});

You'll notice the new variable $btn. This is required because this inside your setTimeout function will no longer refer to the clicked element (a quick search for "javascript scope and this" or similar will explain this further if required). It also doesn't hurt to cache the $(this) result in any case.

Hope that works for you - let me know if I can be of further help.

3
Lelio Faieta On

Try this:

$(document).on('click','#dashboard-actions .btn-restore', function() {

instead of:

$('#dashboard-actions .btn-restore').on('click', function() {

Delegated events must be bind to something that exist in the dom and in the second part will define the element ('#dashboard-actions .btn-restore') you want to trigger click on.

0
Shaunak D On

You need to use event delegation as the class changes dynamically.

$('#dashboard-actions').on('click','.btn-restore', function() {

When you bind the event handler initially, there exists no element with class btn-restore, so the click event after class change does not fire.

Also, I see btn-maximize being altered, of this is later added/toggled I woould suggest using a single common class like 'btn-toggle' and then add/remove btn-maximize/btn-restore. This would prevent adding two separate event handlers.

0
jorge polanco On

check the Jquery Documentation

So maybe you need to put something like this.

using the childs element of #dashboard-actions

$('#dashboard-actions .button').on('click', function() {})

and inside of the function using hasClass documentation

$(this).hasClass('className')