Ok I create element, assign click handler, and append it to body. Then i remove it and reappend it and click handler is no longer working???
Why would this happen.
var btn = $('<button>').text('hi').click(function(){console.log(3);});
var div = $('<div>');
div.append(btn);
$('body').append(div);
//click it now, it works..
div.html('');
div.append(btn);
// now button doesn't work..
So why is this happening and what can i do to fix it.
Since .html('') is essentially the same as .empty(), the following applies (from the jQuery docs):
To avoid memory leaks, jQuery removes other constructs such as data and event handlers from the child elements before removing the elements themselves.
If you want to remove elements without destroying their data or event handlers (so they can be re-added later), use .detach() instead.
One option would be to use event delegation. In doing so, the event isn't bound directly to the button element, it is bound to a constant parent element that isn't removed.
Example Here
$(document).on('click', 'button', function () {
// ..
});
As mentioned above, another option would be to use the .detach() method in order to remove the element from the DOM, without removing attached event listeners.
The .detach() method is the same as .remove(), except that .detach() keeps all jQuery data associated with the removed elements. This method is useful when removed elements are to be reinserted into the DOM at a later time.
Example Here
div.find('button').detach();
div.append(btn);
put this after the second div.append(btn); - > btn = $('button').text('hi').click(function(){console.log(3);});
This is very interesting situation. What happens when you clear div with html('') method. Take a look at source code and you will see that internally jQuery calls jQuery.cleanData(getAll(elem, false));. This method is responsible for removing all the related data for all child elements that have already been removed. This is important in order to avoid memory leaks.
Clearing data also removes events bound with on (and similar) methods, because those event handlers are also stored in internal cache object.
So as the result, even though you removed content of the div, the btn object is still in memory, but the event bound to it previously is gone.
This was the explanation of the problem. The solution is to use dedicated method called detach. It will remove button from the DOM but will keep event data in case element will later be appended again.
// remove element but keep its data
btn.detach();
// append back
div.append(btn);
In situations like this you should not use html('').
It happens because you're calling html() on the DIV that contains the button.
When you call html() with an empty string, it calls empty() internally.
Calling empty() on an element iterates over all the elements inside that element removing all data and events securely.
It does this by calling jQuery.cleanData on the button, which again explicitly calls jQuery.removeEvent, removing all events on the button.
The button is still stored in the variable btn, so it can be appended again, but it has lost all data and any events attached to it because the parent element had html("") called on it.
The solution is to use detach() to remove the element with all the data and events intact, so it can be appended again, or you can attach the event to a parent element that isn't removed, or you could just hide the element, generally there's no reason to remove the element just to reappend it, it's better to hide it.
FIDDLE
Related
How can I save elements to variable, then remove it, but not lose the variable data?
var elements = $('.element');
elements.remove();
elements.insertAfter('.insertAfterElement');
Use .detach() instead of .remove().
From docs:
The .detach() method is the same as .remove(), except that .detach() keeps all jQuery data associated with the removed elements. This method is useful when removed elements are to be reinserted into the DOM at a later time.
From http://api.jquery.com/remove/:
In addition to the elements themselves, all bound events and jQuery
data associated with the elements are removed. To remove the elements
without removing data and events, use .detach() instead.
From http://api.jquery.com/detach/:
The .detach() method is the same as .remove(), except that
.detach() keeps all jQuery data associated with the removed
elements. This method is useful when removed elements are to be
reinserted into the DOM at a later time.
But of course, if you are going to insert it back to the document immediately, there is no point in using that.
$('button').on('click', function() {
$('.element').insertAfter('.insertAfterElement');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Wrapper <span class="element">Element</span></div>
<button>Click me</button>
<div class="insertAfterElement"></div>
From http://api.jquery.com/remove/:
To remove the elements without removing data and events, use .detach() instead.
So you'd use
var elements = $('.element');
elements.detach();
// later:
elements.insertAfter('.insertAfterElement');
However, if you only want to move the elements around immediately, you don't need to explicitly remove them from the DOM at all. Just inserting them in a different position will implicitly remove them from their old position (instead of getting them cloned). So simply use
$('.element').insertAfter('.insertAfterElement');
Let's say I have an element:
<section id="container">
<div id="curious">hey, there</div>
</section>
Then, after the DOM loads, I bind an event to the element, like so:
$('#curious').click(function (){
alert('Are you curious?');
});
Later on, the element gets deleted:
$('#container').html('');
What happens to the bound event? Is it deleted too? Does it linger around? Is it a good practice to clean it up?
According to the jQuery documentation for the .html() method, the event handlers are removed.
This is done to prevent memory leaks.
When .html() is used to set an element's content, any content that was in that element is completely replaced by the new content. Additionally, jQuery removes other constructs such as data and event handlers from child elements before replacing those elements with the new content.
Similarly, the same applies when using the .empty()/.remove() methods as well:
all bound events and jQuery data associated with the elements are removed.
If you want to retain the data and event listeners, use the .detach() method instead. The .detach() method is essentially the same as the .remove() method except for the fact that it keeps all jQuery data associated with the removed elements (which means that you can append the same element after detaching it, and the events would still be bound).
This question already has an answer here:
Difference between remove() and detach() in jQuery [closed]
(1 answer)
Closed 10 years ago.
I m not being able to distinguish between the jquery remove() and detach() method as both are acting same or working same ,plz consider the code:
<script>
$(document).ready(function(){
$("#btn1").click(function(){
$("body").append($("#p1").detach());
});
$("#btn2").click(function(){
$("body").append($("#p2").remove());
});
$("p").click(function(){
$(this).animate({fontSize:"+=1px"})
});
});
</script>
From the docs:
The .detach() method is the same as .remove(), except that .detach() keeps all jQuery data associated with the removed elements. This method is useful when removed elements are to be reinserted into the DOM at a later time.
remove() destroys the element completely. detach() removes the element, keeping its data intact.
The detach method doesn't remove interal jQuery data that are associated with the elements (e.g. event bindings), so it's only if there is any such data that you would see any difference.
To move an element from one place to another in the document, you don't have to remove it or detach it, just append it in the new place:
$("body").append($("#p1"));
You're not going to see a visible difference between the two. This excerpt is taken from the jQuery documentation:
The .detach() method is the same as .remove(), except that .detach() keeps all jQuery data associated with the removed elements. This method is useful when removed elements are to be reinserted into the DOM at a later time.
Please review the API documentation on each of these calls:
jQuery Remove
jQuery Detach
As explained by the documentation, $.detach() retains the associated jQuery data whereas $.remove() removes that data. This data contains things like the bound events, the animation queue and whatever you manually added with $.data().
In your original example, you should be able to notice the difference in the following scenario:
Click the paragraph.
Click the button.
Click the paragraph again.
For #p1 and #btn1, clicking the paragraph the second time will still trigger the click handler and bump the font size. This is because the event handler is stored in the data and is retained by detach(). Thus, when reattaching it to the DOM, the handler is still bound.
For #p2 and #btn2 however, the event handler is removed by remove() and clicking on the paragraph the second time won't do anything.
Side note: you don't need to call detach() when you're immediately appending it to the DOM again. detach() may be interesting if you want to store the element in a variable for a while until it needs to be re-appended (with the same data and behaviour). remove() is commonly used to just destroy an element, also cleaning up any associated data.
I have created a series of custom jQuery events for use in mobile web applications. They work great and have been tested. However, I have run into a small problem which I am having trouble understanding.
I am using .clone() on a few elements within the DOM, which contain a button. The button has some of the custom events bound to it (the events are bound using .on()), but. Unfortunately, when I use jQuery's .clone(), the bindings are not preserved, and I have to add them again.
Has anyone encountered this before, does someone know of a potential work around? I thought that using .on() was supposed to preserve the binding for elements that exist now, or in the future?
I think you should use this overload of the .clone() method:
$element.clone(true, true);
clone( [withDataAndEvents] [, deepWithDataAndEvents] )
withDataAndEvents: A Boolean indicating whether event handlers and data should be copied along with the elements. The default value is false.
deepWithDataAndEvents: A Boolean indicating whether event handlers and data for all children of the cloned element should be copied. By default its value matches the first argument's value (which defaults to false).
Beware that .on() does not actually bind the events to the targets but to the element you are delegating to. So if you have:
$('#container').on('click', '.button', ...);
The events are actually binded to #container. When a click on a .button element occurs, it bubbles up to the #container element The element which triggered the event is evaluated upon the selector parameter of .on() and if it matches, the event handler is executed. This is how event delegation works.
If you clone the element #container, you have to deep clone with events and data for the bindings made with .on() to be preserved.
This would not be necessary if you were using .on() on a parent of #container.
I have a hyperlink with an ID when clicked will perform a certain event using JQuery. JQuery records the existence of this link on document load. Some time during the course of the users visit. I remove that link and the re-add it later. However, that even is not fired off again when that link is clicked after it has been removed and added.
Why is the case and how can I remedy it? Something to do with event binding?? Or shall I just add an onclick attribute?
You've been using a tag like this to add the click event:
$('#speciallink').click(function(){
// do something
return false;
});
This will bind the event to the elements that are selected at that moment.
Removing a link and adding it again, will effectively create a new element, without this event. You can use the "live" method to add rules that will be applied to events matching the rule, even when these elements are created after creating the rule:
$('#speciallink').live("click",function(){
// do something
return false;
});
You will need to bind that event handler to the new element when it is added or you could use live() instead of bind to achieve what you need.
Basically, the event handler references the original element. When that element is removed, even though a new element is added with the same id, it is a different element.
Don't remove the link from the DOM tree. Instead, just toggle its visibility with show() and hide().
Removing the element from the DOM tree with remove() will remove the element and all of its event handlers, even if you add it back with the same id.
If you completely remove the element, you will need to reattach any event listeners to the element when you recreate it.
Alternatively, just hide the element by setting its style to display:none with .show() and .hide()