2
\$\begingroup\$

I have taken a look at several answered questions on Stack Overflow about jQuery's new (since 1.9.1 upgrade)

.on('click','',function(){}

and that you need to delegate. However, in each one, it just provides the solution to fix the issue, but I need a bit more finest or an explanation to why it must be done like that.

Here is my code segment which I have already made it working. My question will follow after the code.

jQuery(document).ready(function($){

    /* Shopping Cart Items */
    $(".header-shopping-cart div .toggle-items").on('click', function(){ // Show/Hide Shopping Cart Items
        if ($(".header-shopping-cart-items").css("display") == "none" && $("#items-amount").html() > 0) {
            $(".header-shopping-cart-items").fadeIn();
            $(this).find("i").removeClass("icon-angle-right").addClass("icon-angle-down");
        }
        else {
            $(".header-shopping-cart-items").fadeOut();
            $(this).find("i").removeClass("icon-angle-down").addClass("icon-angle-right");
        }
        return false;
    });

    $(document).on('click','.header-shopping-cart-items .item a', function(){
        var amount = $("#items-amount").html();
        if (amount > 0) {
            $("#items-amount").html(amount - 1); // Dicrease the amount of SC items
            $(this).parent().slideUp(); // Hide this item
            if (amount - 1 == 0) {
                $(".header-shopping-cart-items").fadeOut(); // When there's no any items in the cart, hide the items block
                $(".header-shopping-cart div .toggle-items i").fadeOut();
            }
        }
        return false;
    });
});

The short end of the code basically have two purpose: one the toggle makes it so that when press a drop down opens up.

The second one (which is where I have confusion on) enables a way to remove (or delete) a row from the drop down.

My questions:

  1. When the HTML used to be static, I can do both the operation of toggling the HTML and the deletion of the row without issues. However when I now append the row, I could no longer remove the row by hitting the second on('click'). So I had to modify it with $(document) and then shift the .header-shopping-cart-items .item a into the delegation position. I don't know why it is that.

  2. Must I use the document as the starting point of the delegation? Is it because these rows are not statically there at first and were actually generated later via an event.

  3. If I want to omit

    jQuery(document).ready(function($){
    //code
    });
    

    I should have done IIFE instead - however is there a "trap" in doing so. Trap as in must I start changing the code structure around in order to achieve the same effect.

Please note that I read this in order to fix my JavaScript up to achieve the current code which works.

\$\endgroup\$
2
\$\begingroup\$

I'm not sure this question really fits into the site but I'm going to answer it anyway.

  1. Since the elements don't exist when the page is loaded you can't add a click event to it (yet). If you try to attach the event handler directly to the elements at this time it won't do anything since the elements don't exist. So instead you attach the click element to the document element (which does exist) and then when the click handler is fired (with a click anywhere on the document) it looks to see if the click event was done on an object that matched the selector you entered at that point. If it was then the click handler is fired.

    That was confusing even to me. Let me try a different way.

    Option 1

    Attempt to attach the event handler to the actual element on page load using the selector.

    $('.class-name').on('click', function(){})
    

    The element does not exist yet so this does nothing.

    Option 2

    Attach the event handler to a static element and provide a delegated selector to test for when the item is clicked.

    $(document).on('click','.class-name', function(){})
    

    This event handler is successfully added to the document object. Now when any click happens within the document, the selector is tested and if a match the function is fired.

  2. No, but you need to use a static element. I used the document but it could be any static element as long as all dynamic elements will be contained within. In your case it might be something like $('.header-shopping-cart-items').on('click', '.item a', function() {}) provided the .header-shopping-cart-items container were static (always there).

    Another option, although much more difficult and probably not worth the effort would be to attach the event handler directly to the item row when you inject it. I wouldn't recommend that approach.

  3. You could look into putting this into a module and calling that module when needed. But I don't know that you would be gaining anything by putting this into a IIFE. And I wouldn't say that IIFEs are preferred over the jQuery.ready function. That said, this whole code could probably be put into a IIFE without any changes. You would just need to put it at the bottom of the document.

\$\endgroup\$
  • \$\begingroup\$ #2) So I could have attached myself to any close static element (a div even) rather than a dom? #3) is a question: I'm basically asking to convert from a document.ready into a non document.ready (since that is the prefered practice) what are the kind of pitfall or if there isn't any really. \$\endgroup\$ – azngunit81 Apr 3 '14 at 5:36
  • \$\begingroup\$ #2) Any static element that is a container of all the items you will need to handle with the event handler. \$\endgroup\$ – nickles80 Apr 3 '14 at 5:38
  • \$\begingroup\$ I put my notes on #3 in an edit to my answer. \$\endgroup\$ – nickles80 Apr 3 '14 at 5:44
  • \$\begingroup\$ My pleasure, I hope it was helpful. \$\endgroup\$ – nickles80 Apr 3 '14 at 17:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.