Detecting when a div's height changes using jQuery

I've got a div that contains some content that's being added and removed dynamically, so its height is changing often. I also have a div that is absolutely positioned directly underneath with javascript, so unless I can detect when the height of the div changes, I can't reposition the div below it.

So, how can I detect when the height of that div changes? I assume there's some jQuery event I need to use, but I'm not sure which one to hook into.


Solution 1:

Use a resize sensor from the css-element-queries library:

https://github.com/marcj/css-element-queries

new ResizeSensor(jQuery('#myElement'), function() {
    console.log('myelement has been resized');
});

It uses a event based approach and doesn't waste your cpu time. Works in all browsers incl. IE7+.

Solution 2:

I wrote a plugin sometime back for attrchange listener which basically adds a listener function on attribute change. Even though I say it as a plugin, actually it is a simple function written as a jQuery plugin.. so if you want.. strip off the plugin specfic code and use the core functions.

Note: This code doesn't use polling

check out this simple demo http://jsfiddle.net/aD49d/

$(function () {
    var prevHeight = $('#test').height();
    $('#test').attrchange({
        callback: function (e) {
            var curHeight = $(this).height();            
            if (prevHeight !== curHeight) {
               $('#logger').text('height changed from ' + prevHeight + ' to ' + curHeight);

                prevHeight = curHeight;
            }            
        }
    }).resizable();
});

Plugin page: http://meetselva.github.io/attrchange/

Minified version: (1.68kb)

(function(e){function t(){var e=document.createElement("p");var t=false;if(e.addEventListener)e.addEventListener("DOMAttrModified",function(){t=true},false);else if(e.attachEvent)e.attachEvent("onDOMAttrModified",function(){t=true});else return false;e.setAttribute("id","target");return t}function n(t,n){if(t){var r=this.data("attr-old-value");if(n.attributeName.indexOf("style")>=0){if(!r["style"])r["style"]={};var i=n.attributeName.split(".");n.attributeName=i[0];n.oldValue=r["style"][i[1]];n.newValue=i[1]+":"+this.prop("style")[e.camelCase(i[1])];r["style"][i[1]]=n.newValue}else{n.oldValue=r[n.attributeName];n.newValue=this.attr(n.attributeName);r[n.attributeName]=n.newValue}this.data("attr-old-value",r)}}var r=window.MutationObserver||window.WebKitMutationObserver;e.fn.attrchange=function(i){var s={trackValues:false,callback:e.noop};if(typeof i==="function"){s.callback=i}else{e.extend(s,i)}if(s.trackValues){e(this).each(function(t,n){var r={};for(var i,t=0,s=n.attributes,o=s.length;t<o;t++){i=s.item(t);r[i.nodeName]=i.value}e(this).data("attr-old-value",r)})}if(r){var o={subtree:false,attributes:true,attributeOldValue:s.trackValues};var u=new r(function(t){t.forEach(function(t){var n=t.target;if(s.trackValues){t.newValue=e(n).attr(t.attributeName)}s.callback.call(n,t)})});return this.each(function(){u.observe(this,o)})}else if(t()){return this.on("DOMAttrModified",function(e){if(e.originalEvent)e=e.originalEvent;e.attributeName=e.attrName;e.oldValue=e.prevValue;s.callback.call(this,e)})}else if("onpropertychange"in document.body){return this.on("propertychange",function(t){t.attributeName=window.event.propertyName;n.call(e(this),s.trackValues,t);s.callback.call(this,t)})}return this}})(jQuery)

Solution 3:

You can use the DOMSubtreeModified event

$(something).bind('DOMSubtreeModified' ...

But this will fire even if the dimensions don't change, and reassigning the position whenever it fires can take a performance hit. In my experience using this method, checking whether the dimensions have changed is less expensive and so you might consider combining the two.

Or if you are directly altering the div (rather than the div being altered by user input in unpredictable ways, like if it is contentEditable), you can simply fire a custom event whenever you do so.

Downside: IE and Opera don't implement this event.

Solution 4:

This is how I recently handled this problem:

$('#your-resizing-div').bind('getheight', function() {
    $('#your-resizing-div').height();
});

function your_function_to_load_content() {
    /*whatever your thing does*/
    $('#your-resizing-div').trigger('getheight');
}

I know I'm a few years late to the party, just think my answer may help some people in the future, without having to download any plugins.

Solution 5:

You can use MutationObserver class.

MutationObserver provides developers a way to react to changes in a DOM. It is designed as a replacement for Mutation Events defined in the DOM3 Events specification.

Example (source)

// select the target node
var target = document.querySelector('#some-id');

// create an observer instance
var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    console.log(mutation.type);
  });    
});

// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };

// pass in the target node, as well as the observer options
observer.observe(target, config);

// later, you can stop observing
observer.disconnect();