3

I have this small sample in which I hoped to see log messages in browser console indicating $scope watcher is working well, but it's unfortunately not the case.

<!doctype html>
<html ng-app="demo">

<head>
    <script src="bower_components/angular/angular.js"></script>
    <script>
    var app = angular.module('demo', ['ng']);
    app.controller('demoCtrl', function($scope) {
        var self = this;

        self.searchText = '';
        $scope.$watch('self.searchText', function(n, p) {
            console.log('searchText changed from', n, 'to', p);
        });

    });
    </script>
</head>

<body ng-controller="demoCtrl as ctrl">
    <input type="text" ng-model="ctrl.searchText" />
</body>

</html>
G. Ghez
  • 3,429
  • 2
  • 21
  • 18

4 Answers4

2

You need to use the alias ctrl (not self) in $scope.$watch(...):

<!doctype html>
<html ng-app="demo">

<head>
    <script src="bower_components/angular/angular.js"></script>
    <script>
    var app = angular.module('demo', ['ng']);
    app.controller('demoCtrl', function($scope) {
        var self = this;

        self.searchText = '';
        $scope.$watch('ctrl.searchText', function(n, p) {
            console.log('searchText changed from', n, 'to', p);
        });

    });
    </script>
</head>

<body ng-controller="demoCtrl as ctrl">
    <input type="text" ng-model="ctrl.searchText" />
</body>

</html>

When ng-controller="demoCtrl as ctrl" is used, Angular creates a link to the controller context object this into the scope: $scope.ctrl.

Dmitri Pavlutin
  • 18,122
  • 8
  • 37
  • 41
  • Now I understand, so documentation here may be incomplete when talking about watching local variable `vm`: https://github.com/johnpapa/angular-styleguide#controlleras-with-vm – G. Ghez Feb 18 '16 at 14:34
  • @G.Ghez Agreed, it's a bit confusing. – Dmitri Pavlutin Feb 18 '16 at 14:35
  • Btw, as I said in a previous question (but in order to maintain feed knowledge here too), Both view and controller have an agreement on a variable name here which create a hard link between them. I'm not so fan of that... – G. Ghez Feb 18 '16 at 14:47
  • @G.Ghez It's more a personal preference. I use the `controller as` syntax. – Dmitri Pavlutin Feb 18 '16 at 14:53
1

Change your $watch to:

$scope.$watch(function() {
    return self.searchText;
  }, function(n, p) {
    console.log('searchText changed from', n, 'to', p);
  });
Niezborala
  • 1,857
  • 1
  • 18
  • 27
  • 1
    if you observe variable assigned to `$scope` you can use string notation, but if it is variable not assign to `$scope` you have to use function. – Niezborala Feb 18 '16 at 14:27
  • I understand. But put it *in your answer*. that will make it a much better answer for future visitors. – random_user_name Feb 18 '16 at 14:44
1

In form you used $scope.$watch watching expression should be part of scope or root scope. So you should change your code like this:

<!doctype html>
<html ng-app="demo">

<head>
    <script src="bower_components/angular/angular.js"></script>
    <script>
    var app = angular.module('demo', ['ng']);
    app.controller('demoCtrl', function($scope) {
        var self = this;

        $scope.searchText = '';
        $scope.$watch('searchText', function(n, p) {
            console.log('searchText changed from', n, 'to', p);
        });

    });
    </script>
</head>

<body ng-controller="demoCtrl as ctrl">
    <input type="text" ng-model="searchText" />
</body>

</html>

or use another form and change you code like this:

<head>
    <script src="bower_components/angular/angular.js"></script>
    <script>
    var app = angular.module('demo', ['ng']);
    app.controller('demoCtrl', function($scope) {
        var self = this;

        self.searchText = '';
        $scope.$watch(function() { return self.searchText; }, function(n, p) {
            console.log('searchText changed from', n, 'to', p);
        });

    });
    </script>
</head>

<body ng-controller="demoCtrl as ctrl">
    <input type="text" ng-model="ctrl.searchText" />
</body>

</html>
Alex Kopachov
  • 723
  • 4
  • 9
0

The answer is simple -

Angular watches the expression on the scope variable and not on the controller instance.

To make the code work you need to do modify the controller code as following

var self = this;

self.searchText = '';
$scope.self = this;
$scope.$watch('self.searchText', function(n, p) {
console.log('searchText changed from', n, 'to', p);
});
VIVEK SHAH
  • 21
  • 3
  • "controller as" build allows to automatically attach controller instance to scope. See: https://github.com/johnpapa/angular-styleguide#controlleras-with-vm – G. Ghez Feb 18 '16 at 14:45