Search code examples
javascriptangularjsangularjs-scope

Use `this.$watch` instead of `$scope.$watch` with 'Controller As'


Currently I am using the Controller As format for scoping controllers.

This works great for keeping the scope of values on the views clear and easy to follow.

<div ng-app="myApp" ng-controller="myController as myctrl">
    <ul>
        <li ng-repeat="contact in myctrl.contacts">
            <input type="text" ng-model="contact.name.first" />
        </li>
    </ul>
</div>

However, when implementing a $watch I am running into problems because it seems to be dependent on $scope so the following will not work.

angular.module('myApp',[])
.controller('myController',['contacts',function(contacts) {
    this.contacts = contacts;

    this.$watch('contacts', function(newValue, oldValue) {
       console.log({older: oldValue, newer:newValue});
    });

}]);

I get undefined is not a function in reference to this not having a method $watch.

Is there a way to $watch a value with the Controller As format?

JS Fiddle


Solution

  • Even with the controllerAs format, the $scope is there.

    In fact what controllerAs does is bind the controller instance's this to the $scope.
    E.g. controller="myController as myctrl" does (behind the scenes): $scope.myctrl = this (where this refers to the myController instance).

    So, you can just inject and use the $scope for watches:

    .controller('myController', function ($scope, contacts) {
        this.contacts = contacts;
    
        $scope.$watch(function () {
            return contacts;
        }, function (newValue, oldValue) {...});
    });