Question

So Chrome apparently has a bug that observing the size of an element with a MutationObserver doesn't work when the element is manually resized.

What should I use instead or in addition to that to make this work in Chrome, too, until the bug is fixed? Should I use the deprecated mutation events or is there another better alternative?

Is there a way to do this nice in AngularJS without using the element object?

Was it helpful?

Solution

In order to watch an element's size, you have the following options:

  • Using a MutationObserver you can watch the element's attributes that change when the element is manually resized. This is a bug in Chrome.

  • You can continually poll the element size with JavaScript in a timer interval, but you've indicated that this is not something you wish to use.

  • Your last option that I am aware of is to use CSS element queries.

The last option works by using the fact that all browsers support overflow events for elements. It will alter the layout of your existing page, forcing the element that you are rezing to be positioned relatively or absolutely. No problem at all if you've got a simple page with simple css, but more complicated layouts may run into issues.

OTHER TIPS

I ran into a similar issue while making a few responsive elements so I just ended up using window.onresize:

window.onresize = function(){
        //do element changes here
        $scope.$apply();
    };

not sure if that's what you're looking for but this approach worked well for me.

My recommendation,

First, set a directive for the element you want to watch the height

Second, in the directive add a empty watcher as said at doc like this

If you want to be notified whenever $digest is called, 
you can register a watchExpression function with no listener.(Since 
watchExpression can execute multiple times per $digest cycle when a 
change is detected, be prepared for multiple calls to your listener.)

directive

scope.$watch( function(){
  scope.elHeight = element.height(); // or element.offsetHeight;
};

Third, set a watcher in controller for this height

cotroller

$scope.$watch('elHeight',  function(newVal, oldVal){
  console.log(newVal, oldVal)
};

Every single $digest means every single Angular-related changes within the scope.

--- edit ---
This covers most of angular-js related events. However it does not cover manual resizing, i.e. window resizing, vanilla javascript resizing, etc.

If I use AngularJS, I would fully use Angular all over the page. Thus,
for that case, I would fire small event to get $digest is called.

Use watcher on scope in Angular

$scope.$watch(function() {
  // whatever element you want to watch
  return $element.height();
}, function(newVal, oldVal) {
  // do something
});

My best bid is that when you resizing any element, is likely to be done within another digest cycle if you use angular fully on your page. To fix that you could manually trigger digestion with $scope.$apply() when you manually resize the element or window.

// example to manual trigger digest with $apply()
app.run(function($window, $rootScope) {
  angular.element($window).on('resize', function() {
    $rootScope.$apply();
  });
});

This is better than setTimeout, because it does waste a lot function calls to retrieve the height. It only retrieve when there a possible change of a state. Also this is also more reliable than MutationObserver and MutationEvents when used across browser. What's more, I don't believe MutationObserver and MutationEvents will monitor the dimension of an element.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top