AngularJS: Better way to watch for height change

Solution 1:

This works by registering a watcher in emHeightSource which is called every $digest. It updates the __height property which is in turn watched in emHeightTarget:

/*
 * Get notified when height changes and change margin-top
 */
.directive( 'emHeightTarget', function() {
    return {
        link: function( scope, elem, attrs ) {

            scope.$watch( '__height', function( newHeight, oldHeight ) {
                elem.attr( 'style', 'margin-top: ' + (58 + newHeight) + 'px' );
            } );
        }
    }
} )

/*
 * Checks every $digest for height changes
 */
.directive( 'emHeightSource', function() {

    return {
        link: function( scope, elem, attrs ) {

            scope.$watch( function() {
                scope.__height = elem.height();
            } );
        }
    }

} )

Solution 2:

You can monitor height change of your element without using Div, just writing a $watch statement:

// Observe the element's height.
scope.$watch
    (
        function () {
            return linkElement.height();
        },
        function (newValue, oldValue) {
            if (newValue != oldValue) {
                // Do something ...
                console.log(newValue);
            }
        }
    );

Solution 3:

May be you should watch for $window' dimensions changes , something like:

.directive( 'emHeightSource', [ '$window', function(  $window ) {

    return {
        link: function( scope, elem, attrs ){

           var win = angular.element($window);
           win.bind("resize",function(e){

              console.log(" Window resized! ");
              // Your relevant code here...

           })
        }
    }    
} ] )

Solution 4:

I used a combination of $watch and resize event. I found without scope.$apply(); in resize event, the height changes on the element is not always picked up by $watch.

   link:function (scope, elem) {
        var win = angular.element($window);
        scope.$watch(function () {
                return elem[0].offsetHeight;
        },
          function (newValue, oldValue) {
              if (newValue !== oldValue)
              {
                  // do some thing
              }
          });

        win.bind('resize', function () {
            scope.$apply();
        });
    };

Solution 5:

This approach avoids (potentially) triggering a reflow every digest cycle. It only checks elem.height() /after/ the digest cycle is over, and only causes a new digest if the height has changed.

var DEBOUNCE_INTERVAL = 50; //play with this to get a balance of performance/responsiveness
var timer
scope.$watch(function() { timer = timer || $timeout(
    function() {
       timer = null;
       var h = elem.height();
       if (scope.height !== h) {
           scope.$apply(function() { scope.height = h })
       }
    },
    DEBOUNCE_INTERVAL,
    false
)