$.replaceWith() but without loosing event handlers and stuff - javascript

I don't want to use live() or on() with delegation :/
Is there any other way to replace the element's HTML code but preserve the element data?

When you replace an HTML element via JavaScript, you remove its DOM node, and thereby all information associated with it.
There are (at least) two ways to deal with this:
before replacing, save the data you need into a temporary variable and inject it after replacing (will most likely not work for event handlers).
use an outer element which carries the data and handlers.

Related

What's the best way to remove event listener on an element?

The jQuery .off() API can only remove the event that was added by using its own on(or bind in jQuery) method, many third-party plugins may add events using pure javascript and because of browser compatibility issues, is there any single line of code that can do this stuff more easily?
If the event handler was added with .addEventListener(), then the only way to remove it is with .removeEventListener() and this means that you need to know the handler function too in order to use .removeEventListener() so if an anonymous function was used as the handler, then there is no way to remove the event listener.
In some circumstances, a heavy handed way to clear all event listeners off a DOM element is to replace it with a new element of the same type (perhaps preserving child elements while doing so). This is obviously a blunt instrument because it will clear all state that was associated with the prior DOM element.
If the event is added by jQuery.on(), you can remove it with jQuery.off().
If the event is added by jQuery.bind(), you can remove it with jQuery.unbind().
If the event is added by pure .addEventListener() in pure javascript , you can remove it with .removeEventListener() .
If event is added by plugin, so you won't be knowing the method how event was added, so to make sure that events are removed, you need to clear the DOM element and create a new element identical to the one that is deleted...

How jQuery's .on/.live works? [duplicate]

I'm curious to know the differences between the bind and live functions.
To me they seem to be almost identical.
I read the benefits of live/bind methods, but it didn't tell me about the differences...
Thanks!
In short: .bind() will only apply to the items you currently have selected in your jQuery object. .live() will apply to all current matching elements, as well as any you might add in the future.
The underlying difference between them is that live() makes use of event bubbling. That is, when you click on a button, that button might exist in a <p>, in a <div>, in a <body> element; so in effect, you're actually clicking on all of those elements at the same time.
live() works by attaching your event handler to the document, not to the element. When you click on that button, as illustrated before, the document receives the same click event. It then looks back up the line of elements targeted by the event and checks to see if any of them match your query.
The outcome of this is twofold: firstly, it means that you don't have to continue reapplying events to new elements, since they'll be implicitly added when the event happens. However, more importantly (depending on your situation), it means that your code is much much lighter! If you have 50 <img> tags on the page and you run this code:
$('img').click(function() { /* doSomething */ });
...then that function is copied into each of those elements. However, if you had this code:
$('img').live('click', function() { /* doSomething */ });
...then that function is stored only in one place (on the document), and is applied to whatever matches your query at event time.
Because of this bubbling behaviour though, not all events can be handled this way. As Ichiban noted, these supported events are click, dblclick mousedown, mouseup, mousemove, mouseover, mouseout, keydown, keypress, keyup.
.bind() attacheds events to elements that exist or match the selector at the time the call is made. Any elements created afterwards or that match going forward because the class was changed, will not fire the bound event.
.live() works for existing and future matching elements. Before jQuery 1.4 this was limited to the following events: click, dblclick mousedown, mouseup, mousemove, mouseover, mouseout, keydown, keypress, keyup
Bind will bind events to the specified pattern, for all matches in the current DOM at the time you call it. Live will bind events to the specified pattern for the current DOM and to future matches in the DOM, even if it changes.
For example, if you bind $("div").bind("hover", ...) it will apply to all "div"s in the DOM at the time. If you then manipulate the DOM and add an extra "div", it won't have that hover event bound. Using live instead of bind would dispatch the event to the new div as well.
Nice read on this: http://www.alfajango.com/blog/the-difference-between-jquerys-bind-live-and-delegate/
Is nowadays (since jQuery 1.7) deprecated using the .on() function - http://api.jquery.com/on/
imagine this scenario:
i have several <img> elements.
$('img').bind('click', function(){...});
add some extra images (using get(), or html(), anything)
the new images don't have any binding!!
of course, since the new images didn't exist when you did the $('img')... at step 2, it didn't bind the event handler to them.
now, if you do this:
i have several <img> elements.
$('img').live('click', function(){...});
add some extra images (using get(), or html(), anything)
the new images do have the binding!!
magic? just a little. in fact jQuery binds a generic event handler to another element higher in the DOM tree (body? document? no idea) and lets the event bubble up. when it gets to the generic handler, it checks if it matches your live() events and if so, they're fired, no matter if the element was created before or after the live() call.
In adition to what they said, I think it's best to try to stick to bind when/where you can and use live only when you must.
All these jQuery methods are used for attaching events to selectors or elements. But they all are different from each other.
.bind(): This is the easiest and quick method to bind events. But the issue with bind() is that it doesn’t work for elements added dynamically that matches the same selector. bind() only attach events to the current elements not future element. Above that it also has performance issues when dealing with a large selection.
.live(): This method overcomes the disadvantage of bind(). It works for dynamically added elements or future elements. Because of its poor performance on large pages, this method is deprecated as of jQuery 1.7 and you should stop using it. Chaining is not properly supported using this method.
Find out more here
I wanted to add to this after having to debug a bit due to my own silliness. I applied .live() to a class of button on my page, assuming that it would just render out the correct ID I was trying to pass on the query string and do what I wanted to do with the ajax call. My app has dynamically added buttons associated with an inventory item. For instance, drill down categories to the 'COKE' button to add a coke to your order. Drill down from the top again, and add 'BUDLITE' - each time I wanted those items to be entered into a table via an AJAX call.
However, since I bound .live() to the entire class of buttons, it would remember each ajax call I had made and re-fire it for each subsequent button! It was a little tricky because I wasn't exactly clear on the difference between bind and live (and the answer above is crystal about it), so I figured I'd put this here just in case somebody was doing a search on this stuff.
There is a way to get the live effect but its kind of nasty.
$(this).unbind('mouseout').bind('mouseout',function(){
});
this will clear the previous and reset the new. It has seemed to work fine for me over time.
Difference between live and livequery is discussed here .

Does a javascript event handler exist in memory even after the DOM element to which it is bound is removed?

Given the following code
<div id="app">
<div id="foo" />
</div>
<script>
$('#foo').bind('click', function(){});
</script>
I plan on replacing the contents of #app [e.g. $('#app').html('...');, or innerHTML = '...';]. I know that I can use jQuery's .remove() which calls a 'destroy' handler that unbinds events. The fact that there is a destroy handler set up to remove events leads me to believe that without unbinding the events, when the DOM element is removed, the handler will still exist in memory.
So, if the DOM element #foo no longer exists, does the handler disappear as well, or does it get lost in browser memory?
jQuery keeps track of event handlers itself, which is part of why you need to use unbind (nowadays it's off) if you're removing the element from the DOM not through a jQuery method (if you use jQuery's empty or remove, as you mentioned it handles this itself inernally). This is so jQuery knows it can release its reference to the handler.
If it weren't for that, then in theory, you wouldn't have to do anything because once the DOM element is removed from memory, it's no longer reachable, and so in theory shouldn't keep the event handler in memory. That's the theory. The reality is very different, it can be very easy to end up with a situation (particularly on IE) where neither the DOM element nor the event handler can get cleaned up because they're each causing the other to stick around — a memory leak. JavaScript has no issue with circular references (it understands them and can release two things that are pointing to each other as long as nothing else is pointing to them), but the DOM part of the browser is likely to be written in a different language with a different garbage collection mechanism (IE uses COM, which uses reference counting rather than reachability). jQuery helps you avoid this pitfall with IE (part of why it keeps track of event handlers), but you have to use unbind (nowadays off) (or remove elements via empty, remove, etc.) as a consequence.
The take away message: As you hook, so shall you unhook. :-) (And/or use jQuery when removing elements, since it will handle this.)
Somewhat related: If you're adding and removing elements a lot, you might look to see if event delegation (which jQuery makes really easy via the delegation signatures for on) might help.
Just happened to read the docs on jQuery's empty() method:
To avoid memory leaks, jQuery removes
other constructs such as data and
event handlers from the child elements
before removing the elements
themselves.

How can I force the DOM to re-eval in Javascript/jQuery?

I am dynamically appending HTML to a webpage and I'm also using jQuery to manage stuff.
When I add HTML code, jQuery ignores its existence.
For example:
$("td.elementToClick").click(...
Will work great with jQuery. But if somewhere in the code I append:
$("tr#myRowToAppend").append("<td class="elementToClick>...</td>");
jQuery will ignore this new element if I click on it.
As jQuery associates the events after the page finishes loading, I need one of two solutions:
- Force the DOM to re eval the page without changing the current layout (I don't wish a refresh, so location.reload() is out of the question).
- Force jQuery to add this new element to it's internal event manager.
I don't wish to use onclick="blabla()", I really need to use jQuery.
How can I accomplish this?
What you are looking for is jQuery live. From docs description: "Binds a handler to an event (like click) for all current - and future - matched element. Can also bind custom events."
There is also a plugin liveQuery that supports a wider range of events if you want.
the live() method will alleviate most of your headaches.
I see this happening more often in IE and with cloned elements, to support IE you have to be much more careful with DOM manipulation.
I also see alot of questions on SO with people having issues of copying/moving dom elements to new parts of the dom without cloning it first, which doesn't workout so well in IE.
So you can use live or when you have to handle events from dynamically inserted DOM elements, make sure you clone them with clone(true) to specify you want the events copied:
$("body").append('<div id="one"></div>");
$("#one").mouseover(function(){});
$("body").append( $("#one").clone(true).attr('id','two') );

Does JQuery have a way to unbind events in random HTML string?

I'm using JQuery to set the HTML inside a div. Something like this:
$(div).html(strHtmlBlob);
strHtmlBlob is a chunk of HTML returned via Ajax from the server. After, it's assigned, I set up some events for elements in the new HTML blob by doing this:
$(div).find("a").click(a_ClickHandler);
That all works perfectly fine. The problem is REMOVING the events. I want to make sure I clean up the DOM properly.
I'm removing the HTML like so:
$(div).html("");
But I can see that the events are still there. Is there a way to clean up events for elements that no longer exist?
Use .remove() instead of .html("")
That will clear the elements and events all at once. JQuery does a lot of cleanup magic under the covers if you let it.
$(div).find('a').unbind('click');
Check out the documentation.
Alternatively, you should empty() it:
$(div).empty();
According to the docs:
Note that this function starting with 1.2.2 will also remove all event handlers and internally cached data.

Categories