I'm an actionscript developer getting into jquery/javascript development. I have a question regarding event handlers and binding/unbinding.
Say for instance that I have for an div with a img element with an onerror event handler in it. If i replace that that div with a new one do i need to remove the eventhandler bound to the img element. Since the img no longer will be in the document will browsers be smart enough to remove it or will I have a caused memory leak?
Comming from actionscript i usually try to constantly remove old eventhandlers. So do i need to do this when writing javascript for web browsers?
The event handlers are added with $('imgElement').error(errorFunction);
If you're binding the events with jQuery just call .remove() on the old element before replacing it, or .empty() if you just want to clear it, both of these clean up event handlers for the element and it's children, or in the case of .empty(), just the children.
If you just replace it, e.g. .html(content) you will leak memory, as any handlers or data for those elements will be left on the $.cache object.
try using firequery, its a firefox plugin that shows all active event listeners and jquery.data()
I'm also curious as to whether it's best practice to unbind() events...
Related
I have a div with class="backdrop". This will be added to DOM when I click a button. To this is bound an event of 'wheel'.
I cannot avoid the binding of the event(happening through library) So i will want to unbind this globally.
I tried : $(".modal-backdrop.am-fade").unbind('wheel');
This works but I have to write this statement after each time the div is added to the DOM. I want something which I can write only once and would apply to all the divs which would be added to the DOM in future
I want something which I can write only once and would apply to all the divs which would be added to the DOM in future
If code in the library you're using is adding elements and binding events to them, you'll have to unbind them as you go, there's no alternative.
If you already have some way of triggering that (the library tells you when it adds a div), then you'll just have to have that code respond to that event.
If you don't already have some way of triggering it, you can use mutation observers to watch for the divs being added so you can unbind them. They're well-supported by modern browsers. Slightly less modern browsers may have sufficient support for the old mutation events that you can use a library that provides a mutation observer polyfill using mutation events (just search for "mutation observer polyfill"). Worst case, on really old browsers, you'll have to poll.
Of course, the best answer is to either stop using the library if it doesn't do what you want, or modify it (this is JavaScript, after all) so it doesn't do what you don't want.
I am registering a click listener on a DOM element via jQuery.on(). If later on that element is removed from the DOM -- maybe indirectly, e.g. by by replacing some parent's content via $(parent).html(...), should I still bother to remove my handler via jQuery.off()?
Even if the element will no longer trigger any event, I am worried about potential memory leaks. Does either jQuery or the browser take care of that and discard all registered handlers once an element is removed from the DOM?
Even if the element will no longer trigger any event, I am worried about potential memory leaks.
This is very good concern. To answer your question, take a look at $.fn.html implementation. From there you will learn that html will try to clean up stored event data:
// Remove element nodes and prevent memory leaks
if (elem.nodeType === 1) {
jQuery.cleanData(getAll(elem, false));
elem.innerHTML = value;
}
So in this case manually calling .off() is not necessary. However..
You need to remember that you should never ever try to remove elements with native methods like removeChild or setting innerHTML, since in this case there will be a memory leak for sure (if some data is stored, events are registered by jQuery, etc.). In this case it's more reliable to actually deregister event handlers with .off method. Or better use event propagation and instead or html('') use $.fn.remove.
It's better to call jQuery.off before removing your node, especially if it's a one page application which can contains a lot of events registered.
Hi I'm developing my view in JS and I'm stuck in binding a click handler for my horizontal layout element. I've tried using Jquery
$("#myHorizontalLayout").bind("click",function(){window.alert()});
Which didn't work then I tried using attachPress with the element which obviously didn't exist. Please help.
Update:
The JS view is the default view of the application.
When on/bind does not work, it could be that the HTML of the control has actually not been created yet at this point in time. But even if you delay the binding, the re-rendering (re-creation of the HTML after changes) would remove your listener, at least when bound on the control itself.
A proper way of doing this is using the generic attachBrowserEvent function available on every control (here: on the layout) which internally handles all the rendering/rerendering stuff, see this example:
http://jsbin.com/hijutunefi/1/edit?html,output
attachBrowserEvent works for any browser event, as it attaches a new browser event listener to the root node of the control. For the most common browser events UI5 does event delegation, so for the "click" event and several others addEventDelegate can also be used, as pointed out by aborjinik.
Alternatively, listening on the <body> level with normal jQuery mechanisms should in general also work.
Which didn't work then I tried using attachPress with the element which obviously didn't exist. Please help.
Does this means that the element on which you are attaching event handler doesn't exists at this point? If this is the case you can hook the handler to some container, upper in the DOM hierarchy which you are sure that exists and filter the click events.
Example:
$("body").on("click", "#myHorizontalLayout", function(){
alert("Hey, you!");
});
As of jQuery 1.7, the .on() method is the preferred method for
attaching event handlers to a document. For earlier versions, the
.bind() method is used for attaching an event handler directly to
elements. Handlers are attached to the currently selected elements in
the jQuery object, so those elements must exist at the point the call
to .bind() occurs.
Reference here
So try replacing bind with on and let me know if it works or not.
For an Ajax application, I'm repeatedly using jQuery's html() method to update a DOM container (overwriting HTML content, then binding elements to event listeners).
Are the event listeners that were attached to the destroyed content correctly removed by jQuery, or is there a risk of memory leaks? (There are already a few related questions out here, but I couldn't find the answer).
Yes, all events and data are cleaned up when you remove or replace content with jQuery methods. It is done using the internal cleanData method.
https://github.com/jquery/jquery/blob/1.9-stable/src/manipulation.js#L242
https://github.com/jquery/jquery/blob/1.9-stable/src/manipulation.js#L746
After my previous question I heve this one, that might be better.
I need to add a lot of items on the page and I see that sometimes appendChild+fregment is faster than innerHTML. Anyway now I would need to know the fastest way to add elements and add event listeners too.
One way I see is to listen on the window object and then filter.
Pros:
Only add once, then never
No memory trap if you forget to remove events listeners before remove as the event is added on the window object
others?
Cons:
Maybe slower?
Slower as we need to filter the items and will listen for everything everyime... maybe too slow at this point, I don't know.
The other way I know is to listen on the created element.
But with innerHTML I think only works with the window object listener.
Any other oppinions?
thanks
Best practice to handle "multiple" event handlers for "many" elements is event delegation, which is basically what you described.
Create a listener on the closest shared parent (document.body will of course do it for any element, but maybe there is another parent node below that).
Performance should not be the issue there. It's far worse to create like 200 event handler functions instead of one.