5

Is there any way to set a jQuery event when some (any one) element changes its own height?

I really can't find out how I can fire thi.s

Like:

$('body *').onHeightChange(function(){

//do somenthing
});
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
itsme
  • 48,972
  • 96
  • 224
  • 345
  • That would be very intense on the proc. Is there specific elements you want monitored? If so, it's not too hard. You just create a timer and watch for the height to be different. – SpYk3HH Dec 18 '12 at 15:35
  • Be more specific, what element(s) you doing this on? – Alex Gill Dec 18 '12 at 15:35
  • Possible duplicate: http://stackoverflow.com/questions/172821/detecting-when-a-divs-height-changes-using-jquery – tungd Dec 18 '12 at 15:35
  • nope i don't have specific element cause of it can be a div as a span, random – itsme Dec 18 '12 at 15:36
  • Doesn't matter, you can do delegate (called indirect event binding now?) like `$('body').on('resize', '*', function(event) {...})` – tungd Dec 18 '12 at 15:39
  • @tungd that is the answer i think, what i'm actually going to do :) – itsme Dec 18 '12 at 15:43
  • @tungd I this that is a very costly event listener and should be avoided when possible. – Robin van Baalen Dec 18 '12 at 15:55
  • 1
    Sorry if I confused anybody, my code snippet will only work with the plugin http://benalman.com/projects/jquery-resize-plugin/. It's meant to help when you don't have a specific element (as in the case of the author). The plugin use timer internally and still work when the element is changed by anything rather than just some specific jQuery functions. @RobinvanBaalen: It does, but not very much as we do not really watch every elements, but wait for the event bubble to the `body`. You can replace `body` with the outer most container of the elements that might change. – tungd Dec 18 '12 at 17:20

4 Answers4

9

Whenever you do something that changes the height of the element, trigger an event.

$("#somelement").slideDown().trigger("heightchange");

Now you can bind to that:

$("body").on("heightchange",function(e){
    var $el = $(e.target); // the element that has a new height.
});

You could even monkeypatch a lot of the jQuery methods that can change the height and have them test the height before and after using the method and trigger the event accordingly. Below is an untested example

var topatch = ["slideup","slidedown","height","width","attr","css","animate"];
$.each(topatch,function(i,method){
    var oldfn = $.fn[method];
    $.fn[method] = function(){
        return this.each(function(){
            var $this = $(this), currHeight = $this.css("height"),
                result = oldfn.apply($this,arguments); 
            // check for promise object to deal with animations
            if ( $.isFunction(result.promise) ) {
                result.promise().done(function(){
                    if ( currHeight != $this.css("height") ) {
                        $this.trigger("heightchange");
                    }
                });
                return;
            }
            if ( currHeight != $this.css("height") ) {
                $this.trigger("heightchange");
            }            
        });
    };
});​
Kevin B
  • 94,570
  • 16
  • 163
  • 180
  • @Badaboooooom this solution doesn't use timers. In my opinion, this is the best solution for your problem. – Robin van Baalen Dec 18 '12 at 15:45
  • i think other guy is right saying i must use **$('body').on('resize', '*', function(event) {...})** – itsme Dec 18 '12 at 15:47
  • the resize event only happens on the window, using it for elements will not work unless you apply code similar to mine to trigger it. https://developer.mozilla.org/en-US/docs/DOM/element.onresize – Kevin B Dec 18 '12 at 15:50
2

I think the only event you can use is the 'DOMSubtreeModified'.

hyankov
  • 4,049
  • 1
  • 29
  • 46
  • maybe MutationEvent ? http://stackoverflow.com/questions/6659662/why-is-the-domsubtreemodified-event-deprecated-in-dom-level-3 – itsme Dec 18 '12 at 15:35
  • DOMSubtreeModified = Deprecated according to MDN. Use mutation observers instead - https://developer.mozilla.org/DOM/DOM_Mutation_Observers – sbeliv01 Dec 18 '12 at 15:38
  • @RobinvanBaalen to me returns 404 don't know why so :/ – itsme Dec 18 '12 at 19:08
  • @RobinvanBaalen ok found that problem was the language try this https://developer.mozilla.org/it/DOM/DOM_Mutation_Observers – itsme Dec 18 '12 at 19:09
  • @Badaboooooom well then, if you got auto-forwarded to a 404 page because the original page isn't available in your language, I suppose that's a bug and you should [report](https://bugzilla.mozilla.org/enter_bug.cgi?product=Mozilla%20Developer%20Network&component=Website) it. – Robin van Baalen Dec 18 '12 at 20:41
1

you should use jQuery mutate which has handlers for width , height and more

http://www.jqui.net/jquery-projects/jquery-mutate-official/

Mahmoud Farahat
  • 5,364
  • 4
  • 43
  • 59
1

I thought about it, and I know you already have your answer, the trigger thing is great idea, but if you really want a simple plugin on all possible elements, you could use what I made below. It's just a simple jQuery plugin that makes use of a timer and a callback function for when a height has changed. See the fiddle for example use. Warning Too many elements on the page could cause issues.

jsFiddle

Dirty Plugin

(function($) {
    if (!$.onHeightChange) {
        $.extend({  
            onHeightChange: function(callBack) {
                if (typeof callBack == "string") {
                    switch (callBack.toLowerCase()) {
                        case "play":
                            $.onHeightChange.init();
                            break;
                        case "stop":
                            try { clearInterval($.onHeightChange.timer); } catch(err) { };
                            break;
                    }
                }
                else if (typeof callBack == "function" || callBack == undefined)
                {
                    $.onHeightChange.callback = callBack;
                    $.onHeightChange.init(callBack);
                }
            }
        });
        $.onHeightChange.timer;
        $.onHeightChange.init = function(callBack) {
            $("body,body *").each(function(i) {
                $(this).data("onHeightChange", { height: $(this).height(), outer: $(this).outerHeight() });
            });
            try { clearInterval($.onHeightChange.timer); } catch(err) { };
            $.onHeightChange.timer = setInterval(function() {
                $("body, body *").each(function(i) {
                    if ($(this).data("onHeightChange").height != $(this).height()) {
                        $(this).data("onHeightChange", { height: $(this).height(), outer: $(this).outerHeight() });
                        if ($.onHeightChange['callback']) {
                            if (typeof $.onHeightChange.callback == "function") return $.onHeightChange.callback .call(this, $(this), $(this).height(), $(this).outerHeight());
                        }
                    }
                });
            }, 100);
        };
    }
})(jQuery);

Example Use

$.onHeightChange(function(ele, height, outer) {
    console.log(ele, height, outer);
});
/*---------------------------------------------*/
$.onHeightChange("stop");
$.onHeightChange("play");
SpYk3HH
  • 22,272
  • 11
  • 70
  • 81