0

My app has elements which change size a lot (menu expansions, infinite scroll, filtering results, etc etc). When this resizing occurs, the elements can get stuck behind a fixed bottom nav bar element, rendering the bottom portion of the element hidden. To address this I created a custom directive that compares window height (minus the nav bar height of course) with the element height. If the element height is greater than the window height minus the nav bar height, then additional margin is added to the bottom of my element so that what was hidden behind the bottom nav bar is now revealed on scroll.

So...it works as it should when it's fired. But for some reason, it doesn't always fire when the element height is changed. The clearest example of what is wrong is when a user clicks a glyph to expand a menu...and the margin is added only every other time on click...but if user clicks the same glyph and then engages with another element, triggering a mouseover event for example, the margin is added, which makes me think it's a digest thing.

Here is the directive with the $watch function:

app.directive('addMargin', ['$window', '$timeout', function($window, $timeout) 
{ return function (scope, element, attribute) {

  var elementMarginBottom = parseInt($window.getComputedStyle(element[0]).marginBottom);
  var container = element;
  var windowHeight = windowHeight = $window.innerHeight;
  var containerHeight = element[0].offsetHeight;

  function addMargin ()
  {
    if ((windowHeight-135) < containerHeight)
    {
      container.css('margin-bottom', 135 + elementMarginBottom + 'px');
      console.log('margin added to', attribute.addMargin, 'total margin is: ', 135 + elementMarginBottom);
    }
    else
    {
      container.css('margin-bottom', elementMarginBottom + 'px');
      console.log('margin removed from', attribute.addMargin, 'total margin is: ', elementMarginBottom);
    }
  }

  scope.$watch( 
    function(){
      return containerHeight = element[0].offsetHeight;
    }, 
    function(){
      // $timeout(function(){
        containerHeight = element[0].offsetHeight;
        console.log('element offset: ', containerHeight);
        addMargin();
      // },100);
  }, true); 

}
}]);

And the directive attribute is placed on the top level container for a particular view like so:

<div class="container basic-search-top-container" 
    ng-class="{'menu-is-visible':srchCtrl.isVisibleFirst}" 
    ng-hide="!srchCtrl.isLoggedIn()" 
    add-margin="search">

So bottom line - I need that $watch to fire everytime the element's height changes. And right now it seems to do so selectively.

shaunmwa
  • 136
  • 9
  • Possible duplicate of [jquery - How to determine if a div changes its height or any css attribute?](http://stackoverflow.com/questions/9628450/jquery-how-to-determine-if-a-div-changes-its-height-or-any-css-attribute). Use an event external to the AngularJS framework to trigger the digest cycle. – georgeawg Mar 19 '17 at 21:35
  • So essentially...need to set a timeout to check OR base it on an event triggered by user? – shaunmwa Mar 19 '17 at 22:24
  • The [MutationObserver API](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) seems interesting but care needs to be taken to prevent unnecessary digest cycles from overwhelming the framework. And a $timeout after relevant model changes is necessary to give the browser time to render DOM. – georgeawg Mar 19 '17 at 23:29

0 Answers0