Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery: How to listen for DOM changes?

Is it possible and how can I listen for changes through the entire DOM tree with jQuery?

My specific issue: I have a 'tooltip' function that displays the contents of the title attribute in a stylish way when you do a hover on any html element. When you do a hover, however, by standard the browser renders the title in its own box. I would like to supress that. So what I've thought of is to move the contents of the title attribute to a custom (HTML5) data-title attribute the first time the page is loaded, and then my tooltip function will work with data-title.

The problem is that later on I might add / remove / change the HTML dynamically, so I need to 'rebind' those elements - change those title attrs again. It would be nice if there was an event listener that would listen for such changes for me and rebind the elements automatically.

like image 233
Tony Bogdanov Avatar asked Feb 28 '12 19:02

Tony Bogdanov


2 Answers

My best guess is that you want to listen to DOM mutation events. You can do that by DOM mutation event as any normal javascript event such as a mouse click.

Refer to this : W3 MutationEvent

Example:

$("element-root").bind("DOMSubtreeModified", "CustomHandler");
like image 173
nightf0x Avatar answered Oct 31 '22 16:10

nightf0x


[edited in reply to research by member Tony]

So, without additional code, this is a bit of a blind shot, but it seems to me there are two things to think about here: 1. the default browser tooltip behaviour; 2. a potentially updated DOM and the ability for your custom tooltips to continue functioning.

Regarding #1: when you bind your custom event to the element, you can use event.preventDefault() so that the tooltips don't appear. This doesn't work properly. So, the workaround to keep using the "title" attribute is to grab the value, push it into the data object (the $.data() function), and then null the title with an empty string (removeAttr is inconsistent). Then on mouseleave, you grab the value out of the data object and push it back into the title. This idea comes from here: How to disable tooltip in the browser with jQuery?

Regarding #2: instead of re-binding on DOM change, you just need to bind once to a listener element that is never expected to be destroyed. Usually this is a container element of some sort, but it can even be document (approximating .live() which is now deprecated) if you really need an all-encompassing container. Here's a sample that uses some fake markup of my own devising:

var container = $('.section');

container.on('mouseenter', 'a', function() {
    var $this = $(this);
    var theTitle = $this.attr('title');
    $this.attr('title', '');
    $('#notatooltip').html(theTitle);   
    $.data(this, 'title', theTitle);
});

container.on('mouseleave', 'a', function() {
    $('#notatooltip').html('');
    var $this = $(this);
    var storedTitle = $.data(this, 'title');
    $this.attr('title', storedTitle);
});

My unrealistic markup (just for this example) is here:

<div class="section">
  <a href="#" title="foo">Hover this foo!</a>
  <div id="notatooltip"></div>
</div>

And a fiddle is here: http://jsfiddle.net/GVDqn/ Or with some sanity checks: http://jsfiddle.net/GVDqn/1/

There's probably a more optimal way to do this (I honestly didn't research if you could bind two separate functions for two separate events with one selector) but it'll do the trick.

You shouldn't need to re-bind based on DOM change, the delegated listener will automatically handle it. And you should be able to prevent default tooltip functionality just by preventing it.

like image 41
Greg Pettit Avatar answered Oct 31 '22 16:10

Greg Pettit