javascriptangularjsangularjs-watch

How to properly use $watch in a directive inside a "controller as" controller?


Here is my JS code. The objective is to create a directive that changes the associated DOM element visibility on a scope variable change, but here I've just replaced the code by an 'alert' intruction to get a minimal (not) working example.

app.directive( 'myDirective', [ function () {
   return {
       restrict: 'A',
       link: function( scope, element, attrs ) {
           scope.$watch( 'configurationMode', function( newValue ) {
               alert("TOTO");
           }, true );
       }
   };
} ]);

app.controller( 'ControlPanelController', function() {
    this.configurationMode = true;

    // and some additional code that 
    // modifies 'configurationMode'
    // in response to UI events
});

And I use the directive in the HTML in a straightforward way:

<div my-directive>
    ...
</div>

alert('TOTO') is called once at the first digest cycle, but not once after that, even though the configurationMode variable changes value (which I can see on the UI). What is wrong with the code?

This is the first time I use the 'controller as' syntax with my controller. Is this the issue here?


Solution

  • You have to attach configurationMode to the scope in your controller. scope.$watch only watches properties on the scope.

    There's a couple hacks for watching variables attached to your controller. One might be using controller as, say controller as $ctrl, then scope.$watch('$ctrl.configurationMode', function(){}).

    I would just using bindings, a two way binding, and pass the value through the bind on your directive... the syntax is different depending on what version of AngularJS/Angular you are using.

    .directive( 'myDirective', [ function () {
       return {
           restrict: 'A',
           scope:{
                configurationMode: '='
           },
           link: function(scope, element, attrs) {
               scope.$watch('configurationMode', function(newValue) {
                   alert("TOTO");
               }, true);
           }
       };
    }]);
    

    then to use it

    <div my-directive configuration-mode="$ctrl.configurationMode"></div>
    

    My AngularJS 1.x is a little rusty so check the docs https://docs.angularjs.org/guide/directive I'm guessing you're using an AngularJS 1.x because you have a restrict: 'A' property on your directive.