2

I have a directive that adds 'fixed' class by:

ng-class='{ "fixed": fixed }'

The directive has the following function:

angular.element($window)
  .on('scroll', function() {
    if (this.pageYOffset >= 480) {
      if (!scope.fixed) {
        scope.fixed = true;
        scope.$apply();
      }
    } else {
      if (scope.fixed) {
        scope.fixed = false;
        scope.$apply();
      }
    }
  });

My question is, should I apply the scope.$apply() like this, so it only fires whenever my variable changes, or is it ok just to write:

angular.element($window)
  .on('scroll', function() {
    if (this.pageYOffset >= 480) {
      scope.fixed = true;
    } else {
      scope.fixed = false;
    }
    scope.$apply();
  });

Maybe there's some use of scope.$watch that I am unaware of?

Idefixx
  • 472
  • 5
  • 21

3 Answers3

3

It doesn't make sense to call scope.$apply() if no update is made. So I would suggest use your first approach which is :

   angular.element($window)
  .on('scroll', function() {
    if (this.pageYOffset >= 480) {
      if (!scope.fixed) {
        scope.fixed = true;
        scope.$apply();
      }
    } else {
      if (scope.fixed) {
        scope.fixed = false;
        scope.$apply();
      }
    }
  });
Zee
  • 8,420
  • 5
  • 36
  • 58
0

Yes. you need run digest cycle manually. When you are modifying scope through an events. using scope.$apply that internally call digest cycle & then update all the scope related binding on view.

Simply modifying angular scope outside on Angular context will need to run digest cycle.

  1. Which Approach is best?

Your 2nd way looks appropriate to me.

  1. Maybe there's some use of scope.$watch that I am unaware of?

Yes, you can use watch which will perform dirty checking & whenever value gets change it will fire a function. By using watch you don't need to worry about digest cycle.

Adding watch window pageYOffset property, instead of using scroll event.

Code

$scope.$watch(function(){ return $window.pageYOffset }, function(newVal, oldVal){
       if (newVal >= 480) {
          scope.fixed = true;
       } else {
          scope.fixed = false;
       }
});
Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
  • I know I have to run scope.$apply, but I am asking which way of running it is the preferred one? – Idefixx May 13 '15 at 10:54
0

Of course you don't have to duplicate scope.$apply() in every if-else branch, so your second example makes more sense. However you can simplify it further:

angular.element($window).on('scroll', function () {
    scope.fixed = this.pageYOffset >= 480;
    scope.$apply();
});

.. because expression this.pageYOffset >= 480 already resolves to true or false.

dfsq
  • 191,768
  • 25
  • 236
  • 258