5

Let's say I have the following HTML:

<div id='content'></div>

I'd like to be alerted when height mutations occur on this element. I was hoping the MutationObserver class would help in this, but here is my problem with it:

document.querySelector('#content').style.height = '100px'

It triggers my callback like expected, however normal user interactions won't trigger this, e.g., http://jsfiddle.net/wq4q9/2/

My question is, what is the best modern approach for checking if an element's height has changed?

No jQuery please.

Etheryte
  • 24,589
  • 11
  • 71
  • 116
Shawn
  • 7,235
  • 6
  • 33
  • 45
  • 1
    The usual work-around here is to register event handlers for those events which can cause a height change (e.g. window resize, other specific operations in your page, etc...) and then check the height of that object after each one of these other operations occurs. – jfriend00 Jun 01 '14 at 17:26
  • 1
    Side note: jQuery wouldn't help you here anyway, other than making it really easy to get the height. :-) – T.J. Crowder Jun 01 '14 at 17:26
  • This is not a duplicate of [the Chrome bug](http://stackoverflow.com/questions/20294828/manually-resizing-an-element-doesnt-fire-a-mutation-observer-in-chrome). Firefox has the same behavior, and there are other ways to resize the element that don't fire mutation observers (and arguably shouldn't). – T.J. Crowder Jun 01 '14 at 17:28
  • 1
    @T.J.Crowder put that there mostly to filter out answers with links to jquery plugins – Shawn Jun 01 '14 at 17:29
  • Humm. FWIW, if you `target` the textarea rather than `#content` in your fiddle, it works in Firefox (in reference to the proposed dupe http://stackoverflow.com/questions/20294828/manually-resizing-an-element-doesnt-fire-a-mutation-observer-in-chrome). Your current fiddle is sort-of comparing apples and oranges, as you're asking us to manually resize the textarea, but programatically resize `#content`. If you programatically resize `textarea` instead, the MutationObserver won't fire (http://jsfiddle.net/wq4q9/4/). – Matt Jun 01 '14 at 17:32
  • @Matt that's interesting about firefox. Also your fiddle probably showcases the problem better – Shawn Jun 01 '14 at 17:45

2 Answers2

1

I don't think there's anything you can do other than poll. (Another way your observer wouldn't be triggered would be if you changed a CSS rule that applied to the element, changed its parent's size and its size was dependent on that, added a new style sheet that affected it...)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Example of changing parent's size not firing a mutation observer: http://jsfiddle.net/wq4q9/3/ – T.J. Crowder Jun 01 '14 at 17:36
  • Thanks T.J -- I'll probably end up polling :) – Shawn Jun 01 '14 at 17:49
  • T.J: Why should we be expecting the changing of the parent's height to trigger the `MutationObserver`? The element the observer is attached to still isn't being *affected* is it? – Matt Jun 01 '14 at 17:56
  • 1
    @Matt: It is if (as I said somewhat in passing above) its size was dependent on its parent's size. In the fiddle I did that with `height: 100%`. Changing the parent's height changes the target's height, but doesn't fire a mutation observer callback. – T.J. Crowder Jun 01 '14 at 17:57
  • 1
    @T.J.Crowder: Ahh, I'm with you... because `#content` has `height: 100%`. I should probably have noticed the massive blue box getting bigger when clicking the button, but instead I needed it spelling out for me :P. – Matt Jun 01 '14 at 17:59
1

You'll probably have to go along with T.J. Crowders recommendation to poll, however your code example isn't working for other reasons (it seems):

The documentation* for childList says that it is used to monitor additions and removals of the target node's child elements.

* This is the first and only time I'll reference MSDN as opposed to MDN, because the MDN documentation for this is crap.


The record you should be observing is subtree:

Set to true to also monitor changes to all the target node's descendants


If you do that, then the code works in Firefox.

var target = document.querySelector('#content');

var observer = new MutationObserver(function(mutations) {
  console.log(mutations);   
});

var config = { attributes: true, childList: true, subtree: true, characterData: true };
observer.observe(target, config);

document.querySelector('button').addEventListener('click',function(){
    target.style.height = '200px';
});

However, it still doesn't work in Chrome; likely because of the Chrome bug reported in this question.

Community
  • 1
  • 1
Matt
  • 74,352
  • 26
  • 153
  • 180