2

I'm using a directive to check how much the user is scrolling the window but I can't manage to bind the scope with the controller.

Here's the directive and controller code:

'use strict';

angular.module('myApp.landing', ['ngRoute'])

.config(['$routeProvider', function($routeProvider) {
}])
.controller('landingCtrl', ["$scope", function($scope) {
    $scope.scrolled = false;

    $scope.$on('$routeChangeSuccess', function() {
    });
}]).
directive("scroll", ["$window", function($window){
    return {
        scope: false,
        link: function($scope, element, attrs){
            angular.element($window).bind("scroll", function(){
                if (this.pageYOffset >= 150) {
                     $scope.scrolled = true;
                     console.log($scope.scrolled + 'Scrolled 100px');
                 } else {
                     $scope.scrolled = false;
                     console.log($scope.scrolled + 'Not scrolled enough');
                 }
            });
        }
    };
}]);

this is the view code:

<div ng-controller="landingCtrl" scroll>
    <div class="row">
        <div class="col-sm-12 col-md-9 landing-square">{{ scrolled }}</div>
        <div class="col-sm-12 col-md-3 landing-square"></div>
        ....
</div>

In the view scrolled is not defined. If I define it in the controller I can see it, but the directive can't change its value. Basically I want in the view the variable "scrolled" that is changing value according to the directive.

What am I missing?

ste
  • 3,087
  • 5
  • 38
  • 73

2 Answers2

0

Because you're changing a something on the scope in a place Angular does not "know" about (e.g. a custom DOM event handler), you need to explicitly tell it to apply that change:

angular.element($window).bind("scroll", function(){
    if (this.pageYOffset >= 150) {
         $scope.$apply(function() { $scope.scrolled = true; });
         console.log($scope.scrolled + ' Scrolled 100px');
     } else {
         $scope.$apply(function() { $scope.scrolled = false; });
         console.log($scope.scrolled + ' Not scrolled enough');
     }
});

See this example, and see this excellent Q&A on $scope $apply and $watch. Or just go straight to the relevenat documentation (which is dry/technical, but explains the reasoning bhind it as well).

Community
  • 1
  • 1
Jeroen
  • 60,696
  • 40
  • 206
  • 339
  • The documentation says that $apply is used to "execute an expression in angular from outside of the angular framework". But why my directive should be outside the angular framework? – ste May 23 '16 at 12:37
  • The `.bind(....` handler is considered to be a source "outside the Angular framework", where the `$scope.scrolled` variable is changed. Typical things considered to be "inside" the framework are `ng-click` handlers and so on. – Jeroen May 23 '16 at 12:42
0

In the directive, you are changing the scope values.
Try to apply the changes to the scope.

$scope.scrolled = true;     
$scope.$apply();
Priya
  • 1,359
  • 6
  • 21
  • 41
Nifal Nizar
  • 895
  • 1
  • 8
  • 17