jquery click event not firing on dynamically creat

2019-03-04 11:07发布

问题:

i'm setting a click event on a div that is dynamically created in a jqueryUI drop event (part of draggable), the click event will remove the div. That works fine. Inside of document.ready I do the same thing, based on data from local storage. I can create the dynamic divs, but the click event does not bind, or the binding is lost. I've tried using "click", "live" and "on". I've also removed the loop it sits in and just attached to the first item, none of it works when sitting directly in $(document).ready, but works fine when I set the click in the drop event.

this works: binding from droppable

$( "#planView" ).droppable({
            drop: function( event, ui ) {
                if(ui.draggable.find(".planButton").length == 1){
                    // make unique ID,add ID to last child,add click event last child,add plan to model with plan data and ID 
                    var id      = ui.draggable[0].id; // we use the id to grab the right cart html and cart data
                    var id      = id.substring(0, id.length-6);
                    var newPlan;
                    var newID;
                    var planData;

                    $( this ).append(planCartObjects[id]);
                    newPlan         = $( this ).find('>:last-child');
                    newID           = "cartObject"+cartIDcounter++;
                    newPlan.attr("id",newID);
                    planData        = $.extend(true,{},planDataObjects[id]); //makes a copy of the data object
                    planData.id     = newID;
                    shoppingCart.addPlan(planData);
                    shoppingCart.logCart();
                    newPlan.click(function(){
                        //remove element
                        $(this).remove();
                        shoppingCart.removePlan(newID);
                        console.log("newID "+newID);
                    });
                }
            }

this does not work - called once on document.ready

    $(document).ready(function() {
        //check local storage 
        //if yes create plan and or feature cart objects
        //populate model
        var cartIDcounter       = 0;
        var localStorageKey     = "vlocalstore234"; 
        var shoppingCart;

        shoppingCart            = shoppingCartMaker({});

        if(localStorage.getItem(localStorageKey)){
            //grab cartModel, clear out local storage, calladdplan ans addfeature in a loop to create htmls objs and data obj
            var cartModel = JSON.parse(localStorage.getItem(localStorageKey));
            localStorage.removeItem(localStorageKey);
            //update cart with saved features and plans
            var i;
            var l                   = cartModel.plans.length;
            var newPlan;
            var newID;
            var planData;
            var id;

            for(i=0;i<l;i++){
                console.log(cartModel.plans[i].name);   
                id                  = cartModel.plans[i].name
                $( "#planView" ).append(planCartObjects[id]);
                    newPlan         = $( this ).find('>:last-child');
                    newID           = "cartObject"+cartIDcounter++;
                    newPlan.attr("id",newID);
                    planData        = $.extend(true,{},planDataObjects[id]); //makes a copy of the data object
                    planData.id     = newID;
                    shoppingCart.addPlan(planData);
                    shoppingCart.logCart();
                    newPlan.on("click",function(){
                        //remove element
                        $(this).remove();
                        shoppingCart.removePlan(newID);
                        console.log("newID "+newID);
                    });
            }

complete code block

    $(document).ready(function() {
        //check local storage 
        //if yes create plan and or feature cart objects
        //populate model
        var cartIDcounter       = 0;
        var localStorageKey     = "vlocalstore234"; 
        var shoppingCart;

        shoppingCart            = shoppingCartMaker({});

        if(localStorage.getItem(localStorageKey)){
            //grab cartModel, clear out local storage, calladdplan ans addfeature in a loop to create htmls objs and data obj
            var cartModel = JSON.parse(localStorage.getItem(localStorageKey));
            localStorage.removeItem(localStorageKey);
            //update cart with saved features and plans
            var i;
            var l                   = cartModel.plans.length;
            var newPlan;
            var newID;
            var planData;
            var id;

            for(i=0;i<l;i++){
                console.log(cartModel.plans[0].name);   
                id                  = cartModel.plans[0].name
                $( "#planView" ).append(planCartObjects[id]);
                    newPlan         = $( this ).find('>:last-child');
                    newID           = "cartObject"+cartIDcounter++;
                    newPlan.attr("id",newID);
                    planData        = $.extend(true,{},planDataObjects[id]); //makes a copy of the data object
                    planData.id     = newID;
                    shoppingCart.addPlan(planData);
                    shoppingCart.logCart();
                    newPlan.live("click",function(){
                        //remove element
                        $(this).remove();
                        shoppingCart.removePlan(newID);
                        console.log("newID "+newID);
                    });
            }       
            l                       = cartModel.features.length;
            for(i=0;i<l;i++){
                console.log(cartModel.features[i].name);    
                id                  = cartModel.features[i].name;
                $("#featureView").append(featureCartObjects[id]);
                newPlan             = $( this ).find('>:last-child');
                newID               = "cartObject"+cartIDcounter++;
                newPlan.attr("id",newID);
                featureData         =  $.extend(true,{},featureDataObjects[id]);
                featureData.id      = newID;
                shoppingCart.addFeature(featureData);
                shoppingCart.logCart();
                newPlan.click(function(){
                    //delete view and remove from model
                    $(this).remove();
                    shoppingCart.removeFeature(newID);
                    console.log("newID "+newID);                    
                    //remove from model

                });
            }
        }

        //Plans drag and drop
        $( "#myPlans span" ).draggable({
            start: function(event, ui) {},
            stop: function(event, ui) {  
                $( "#chooser span" ).css({'top':'0px', 'left':'0px'});
            }
        });
        $( "#planView" ).droppable({
            drop: function( event, ui ) {
                if(ui.draggable.find(".planButton").length == 1){
                    // make unique ID,add ID to last child,add click event last child,add plan to model with plan data and ID 
                    var id      = ui.draggable[0].id; // we use the id to grab the right cart html and cart data
                    var id      = id.substring(0, id.length-6);
                    var newPlan;
                    var newID;
                    var planData;

                    $( this ).append(planCartObjects[id]);
                    newPlan         = $( this ).find('>:last-child');
                    newID           = "cartObject"+cartIDcounter++;
                    newPlan.attr("id",newID);
                    planData        = $.extend(true,{},planDataObjects[id]); //makes a copy of the data object
                    planData.id     = newID;
                    shoppingCart.addPlan(planData);
                    shoppingCart.logCart();
                    newPlan.click(function(){
                        //remove element
                        $(this).remove();
                        shoppingCart.removePlan(newID);
                        console.log("newID "+newID);
                    });
                }
            }
        });

        //features drag and drop
        $("#addOnFeatures span").draggable({
            start: function(event, ui){},
            stop: function(event, ui){
                $("#addOnFeatures span").css({'top':'0px', 'left':'0px'});
            }
        });
        $("#featureView").droppable({
            drop: function(event, ui){
                if(ui.draggable.find(".featureButton").length == 1){
                    var id          = ui.draggable[0].id;
                    var id          = id.substring(0, id.length-6);
                    var newPlan;
                    var newID;
                    var featureData;
                    var mydata;

                    $( this ).append(featureCartObjects[id]);
                    newPlan         = $( this ).find('>:last-child');
                    newID           = "cartObject"+cartIDcounter++;
                    newPlan.attr("id",newID);
                    featureData     =  $.extend(true,{},featureDataObjects[id]);
                    featureData.id  = newID;
                    shoppingCart.addFeature(featureData);
                    shoppingCart.logCart();
                    newPlan.click(function(){
                        //delete view and remove from model
                        $(this).remove();
                        shoppingCart.removeFeature(newID);
                        console.log("newID "+newID);                    
                        //remove from model

                    });
                }
            }
        });
    });

回答1:

I think your problem lies with the $(this) before your selector. What does $(this) refer to in the .ready() scope?



回答2:

Heres your issue.

The reason .on works is because it delegates events to an element that already exists, like the document, body, or some static parent element not inserted after the dom load, and when that element is acted on based on the FIRST paramenter (click, blur, etc), then it will ask to check if the second parameter is a function or a valid selector.

newPlan.on("click",function(){
    .... 
})

should be

$someParentElement.on("click", '.newPlanSelector', function(){
    .... 
})

This is because events can not be bound to non existent element. Ff you bind some events, then add a that element, all events will be nullified. The way to get around this is to bind to a static element.

Since events bubble from the clicked element, upwards through the DOM tree, they hit every node on the way up. This event will have the source elements info (class/id/etc). Now, this is good because we can't nececarrily tell the element that doesn't exist what to do when it's clicked if we're unsure it exists (or even if we try) but we CAN tell a static parent of this object to act when it recieves a certain type of event (click, blur, etc) from a specified target (list item, link, etc).

Event delegation is the official term.

Happy hunting!:)

Update: Also, ensure you don't use ($(this)) as A.A. posted, this is often an issue. Use $.proxy(function() { }) and call REAL values.

this.$someParent is good object naming :) this.someParent is bad object naming :)

Just some random tips. Don't expect an accepted answer outa this one :P



回答3:

The live event binding has to be set on a selector for it to be attached to click event when a new div is dynamically created. You are doing a $.find(), which would only search within the current element, and attach the click event to the elements that were found. The solution for your issue would be to attach the click event using "$.live()" on a selector.