Giulio Bambini
Giulio Bambini

Reputation: 4755

If hasClass condition jquery not working properly

I was trying to execute some alerts with some onclick events and conditions with jquery statement. But it seems that event handlers don't work properly, probably due the fact that is missing something in my event handling logic. I have just 1 button, with id #bottone1, and I have some menu buttons with id #b1 and #b2.

The first event works fine, it adds correctly the class "cliccatoInvoca1_OnReady". When i click on #bottone1 it starts the the first alert "cliccatoInvoca1_OnReady". Also the onClick event $("#b1") works properly, it removes the class "cliccatoInvoca1_OnReady" and replaces with the class "cliccatoInvoca1".

This point i encounter the first problem

When i click on #bottone1 it comes like first alert "cliccatoInvoca1_OnReady", and then "cliccatoInvoca1". Then when i click on #b2 and afer that i click on #bottone1 it executes 3 alerts, "cliccatoInvoca1_OnReady", "cliccatoInvoca1" and finally "cliccatoInvoca3".

So, the main problem is that it doesn't work if condition for execute only 1 alert at time. So when i click on #bottone1 it executes all the alerts in sequence.

This is my document.ready function

$(document).ready(function () {
    $("#select-1").multiselect();
    invoca1();
    $("#bottone1").addClass("cliccatoInvoca1_OnReady btn btn-default");
    if ($("#bottone1").hasClass("cliccatoInvoca1_OnReady")) {
        $("#bottone1").click(function () {
            alert("cliccatoInvoca1_OnReady");
            keys = [];
            $('input[name="multiselect_select-1"]:checked').each(function () {
                keys.push(this.value);
            });
        });
    }

    $("#b1").click(function () {
        invoca1();
        $("#bottone1").removeClass("cliccatoInvoca1_OnReady noClass").addClass("cliccatoInvoca1");
        if ($("#bottone1").hasClass("cliccatoInvoca1")) {
            $("#bottone1").click(function () {
                alert("cliccatoInvoca1");
                keys = [];
                $('input[name="multiselect_select-1"]:checked').each(function () {
                    keys.push(this.value);
                });
            });
        }
    });

    $("#b2").click(function () {
        invoca3();
        $("#bottone1").removeClass("cliccatoInvoca1").addClass("cliccatoInvoca3");
        if ($("#bottone1").hasClass("cliccatoInvoca3")) {
            $("#bottone1").click(function () {
                alert("cliccatoInvoca3");
                keys = [];
                $('input[name="multiselect_select-1"]:checked').each(function () {
                    keys.push(this.value);
                });
            });
        }
    });
});

Upvotes: 0

Views: 780

Answers (1)

iCollect.it Ltd
iCollect.it Ltd

Reputation: 93561

Change to use delegated event handlers, attached to a non-changing ancestor element, each with a matching selector:

e.g. like this:

$(document).on('click', "#bottone1.cliccatoInvoca1_OnReady", function() {
    alert("cliccatoInvoca1_OnReady");
    keys = [];
    $('input[name="multiselect_select-1"]:checked').each(function () {
         keys.push(this.value);
    });
});

The above is now all you need for one click handler, repeat the pattern for the other classes it can have. You never need the hasClass checks.

Your other code just becomes simple like this:

$("#b1").click(function () {
     invoca1();
     $("#bottone1").removeClass("cliccatoInvoca1_OnReady noClass").addClass("cliccatoInvoca1");
 });

Delegated handlers:

  • Delegated event handlers work by listening for the event (in this case click) to bubble up to the ancestor element.
  • You normally choose the closest non-changing ancestor element, but document is the default if nothing else is closer/convenient. Do not use 'body' as it has a bug related to styling that can cause mouse events not to bubble to it.
  • Then it applies the jQuery selector to only the elements in the bubble-chain.
  • It then applies the function, only to the matching elements that caused the event.
  • The result is the elements only need to match at event time and not event registration time.

This pattern will simplify your code significantly.

The entire example will become something like this:

$(document).ready(function () {
    $("#select-1").multiselect();
    invoca1();
    $("#bottone1").addClass("cliccatoInvoca1_OnReady btn btn-default");

    $("#b1").click(function () {
        invoca1();
        $("#bottone1").removeClass("cliccatoInvoca1_OnReady noClass").addClass("cliccatoInvoca1");
    });

    $("#b2").click(function () {
        invoca3();
        $("#bottone1").removeClass("cliccatoInvoca1").addClass("cliccatoInvoca3");
    });

    $(document).on('click', "#bottone1.cliccatoInvoca1", function () {
        alert("cliccatoInvoca1");
        keys = [];
        $('input[name="multiselect_select-1"]:checked').each(function () {
            keys.push(this.value);
        });
    });

    $(document).on('click', "#bottone1.cliccatoInvoca3", function () {
        alert("cliccatoInvoca3");
        keys = [];
        $('input[name="multiselect_select-1"]:checked').each(function () {
            keys.push(this.value);
        });
    });
});

Notes:

  • I am ignoring the fact that your event handlers contain identical code and assume the real code has different operations.

Upvotes: 5

Related Questions