Skip to content Skip to sidebar Skip to footer

Cloning A Bootstrap Element With An Event Listener

I'm trying to clone a bootstrap element that has data-toggle behavior provided by bootstrap: HTML

BUT

You need to handle events for dynamic objects using event delegation technique.

 $(document).on("click",".btn",function(){ .... });

This will work, because the event handler is bound to an element higher up the DOM tree (in this case, the document) and will be executed when an event reaches that element having originated on an element matching the selector, And that's what Bootstrap does for dynamic objects, also you do the same if needed for dynamic objects. Hers is JSFiddle for this.

Also you need to wrap the whole collapsible part in a div for cloning.

Note: Using .clone() has the side-effect of producing elements with duplicate id attributes, which are supposed to be unique. Where possible, it is recommended to avoid cloning elements with this attribute or using class attributes as identifiers instead.

So, you need to update data-target and divid attribute after cloning, so that newly created button targets the newly created collapse panel

I am using jQuery for it.

Here is the code Snippet

$(function(){
  var target = "collapsible_obj_";
  var i = 1;
  
  $("#button").click(function(){
    $(".parent_colapse:last").clone().insertAfter(".parent_colapse:last");        
    $(".parent_colapse:last > button").attr("data-target", "#"+target+i);
    $(".parent_colapse:last .collapse").attr("id", target+i);
    i++;
  });
  
  $(document).on("click",".button",function(){
     alert();
  });
});
<linkhref="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" /><scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><scriptsrc="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script><divclass="parent_colapse"><buttonaria-expanded="false"data-target="#collapsible_obj_0"data-toggle="collapse"class="btn btn-link collapsed">click here</button><divstyle="height: 0px;"aria-expanded="false"id="collapsible_obj_0"class="collapse"><span>foo</span><buttontype="button"class="button">click</button></div></div><buttontype="button"id="button">Clone</button>

About your question you haven't shown your full script that's the reason we are unable to find the bug. LIKE we don't know objectContainer nor collapsibleObjCounter what that is ?

Solution 2:

Don't copy the events while cloning, remove the true flag.

var header = objectContainer.clone();

My guess is Bootstrap is handling the event binding of dynamic objects also for data-toggle, it only needs to have different id's & target.

Here's a fiddle.

PS: Don't know what was this or objectContainer in OP's question, so created a closure and pasting result in new wrapper.

Solution 3:

The problem is not caused by the event listeners in and of themselves. The issue is how Bootstrap works. For most of the Bootstrap components, Bootstrap creates a JavaScript object associated with the DOM element. This object is what you need to take care of when you clone Bootstrap components. For a collapse element, Bootstrap creates a Collapse object.

The JavaScript object is associated with the DOM element through jQuery's $.data. This is the problem. If you use jQuery's clone and request that event handlers be copied to the clone, then you also get a copy of the data set with $.data. However, when the data is a reference to a JavaScript object, then it is the reference that is copied to the clone. So the original and the clone refer to the same JavaScript object and this is where everything goes astray. This is not special to Bootstrap, by the way: any reference is subject to this problem.

What you could do is perform a $.removeData on the cloned elements that are Bootstrap components. This will force Bootstrap to recreate the JavaScript object. For components that automatically enroll in the data API, this should be all that's needed. (collapse automatically enrolls.) For components that do not automatically enroll (e.g. tooltips), you need to call $.[component] to recreate the component manually.

I've forked a fiddle from aManHasNoName's fiddle that illustrates this. The only modifications were:

  1. Add the parameters true, true to var header = objectContainer.clone();

  2. Modify header.find(".collapse").attr("id", collapseId) to add .removeData() at the end.

Solution 4:

I have created a JSFiddle of your code. The most possible error seems to that you where using a this.collapsibleObjCounter++ value of 0 that might be creating an issue.

Here is a working JSFiddle. Please let me know if that is what you are trying to do. Thank you.

https://jsfiddle.net/2fgoywzy/1/


JS

$( document ).ready(function() {
for (i = 1; i < 5; i++) { 
    var objectContainer =  $("#main");
    var header = objectContainer.clone(true);
    var counter = i; // replace this with this.collapsibleObjCounter++var collapseId = "collapsible_obj_" + counter;

    header.find(".collapse").attr("id", collapseId);
    header.find("button[data-toggle='collapse']").attr("data-target", "#"+collapseId);
    $(header).appendTo('body');
}
});

HTML

<divid="main"><buttonaria-expanded="false"data-target="#collapsible_obj_0"data-toggle="collapse"class="btn btn-link collapsed">click here</button><divstyle="height: 0px;"aria-expanded="false"id="collapsible_obj_0"class="collapse"><span>foo</span></div></div>

If you are having a value of 0 in this.collapsibleObjCounter++ then i would suggest doing ++this.collapsibleObjCounter. Instead of post increment do pre increment

Post a Comment for "Cloning A Bootstrap Element With An Event Listener"