user3429672
user3429672

Reputation: 237

How to have a directive update in the page is scrolled or resized

I have an directive which sets two classes to an element to identify which quadrant it is in the browser window (top left, top right, bottom left, bottom right). Code is similar to this:

angular.module('positionerDirective', [])
  .directive('positioner', function() {
    return {
      restrict: 'A',
      link: function(scope, element){
        var top = element[0].offsetTop;
        var left = element[0].offsetLeft;
        //do whatever math you need here
        angular.element(element).addClass(class you need);
      }
    };
  });

The problem I have is that if the user scrolls, or changes the screen size, the quadrant could change, and I need the classes to update if this happens. So my question is, how can I make the directive run again if the left / top changes?

Upvotes: 1

Views: 77

Answers (1)

Vadim
Vadim

Reputation: 8789

You can add controller to your directive, subscribe in it to DOM events of resize and scroll and update class accordingly. Here is an example of doing it:

JavaScript

angular.module('positionerDirective', []).
  directive('positioner', function() {
    return {
      restrict: 'A',
      scope: true, // <- create isolated scope
      link: function(scope, element) {
        var el = element[0];
        scope.$watch(function() {
          return (el.offsetTop - scope.scrollTop)+':'+(el.offsetLeft - scope.scrollLeft); // <- check element class is to be updated
        }, function() {
          el.className = 'top-'+(el.offsetTop - scope.scrollTop)+' left-'+(el.offsetLeft - scope.scrollLeft); // <- apply new element class
        });
      },
      controller: ['$scope', '$window', function($scope, $window) {
        $scope.updatePosition = function() {
          $scope.scrollTop = $window.document.body.scrollTop,
          $scope.scrollLeft = $window.document.body.scrollLeft;
          if ($scope.$root.$$phase != '$apply' && $scope.$root.$$phase != '$digest') { // <- Avoid call of $apply while digest is already running
            $scope.$apply();
          }
        }
        angular.element($window).on('resize scroll', function() { // <- subscribe to DOM events and update scope accordingly
          $scope.updatePosition();
        });
        $scope.updatePosition(); // <- set initial values of $scope.scrollTop and $scope.scrollLeft
      }]
    };
  });

Plunker: http://plnkr.co/edit/wvYTZ18gY2N5ABODyZO7?p=preview

Upvotes: 1

Related Questions