ps0604 ps0604 - 2 months ago 10
AngularJS Question

Accessing child scope in watch

In this plunk I have two nested directives, each with a checkbox. My objective is to change the parent checkbox whenever the user clicks on the child checkbox. I need to use watch (no messages), but I cannot access the child scope. Any ideas?

Javascript

angular.module('app', []);


angular.module('app')
.directive('directive1', function()

var directive = {};

directive.restrict = 'E';

directive.scope = true;

directive.template = '<input type="checkbox" ng-model="cb1"> Top directive <br/><directive2></directive2> ';

directive.link = function(scope, element, attrs) {

scope.$watch(function () {'cb2' },
function (newValue, oldValue) {
scope.cb1 = newValue;
});


};

return directive;

});


angular.module('app')
.directive('directive2', function() {

var directive = {};

directive.restrict = 'E';

directive.scope = true;

directive.template = '<input type="checkbox" ng-model="cb2"> Bottom directive ';

directive.link = function(scope, element, attrs) {
};

return directive;

});

Answer

For prototypical inheritance to work correctly, the ng-model directive needs to have a value with a "dot".

<input type="checkbox" ng-model="d1.cb2">

Then the parent directive needs to create the d1 object and watch d1.cb2.

angular.module('app')
.directive('directive1', function() {
    var directive = {};
    directive.restrict = 'E';
    directive.scope = true;
    directive.template = '<input type="checkbox" ng-model="cb1"> Top directive <br/><directive2></directive2> ';

    directive.link = function(scope, element, attrs) {
      scope.d1 = {};
      scope.$watch('d1.cb2', 
                    function (newValue, oldValue) {
                       scope.cb1 = newValue;  
                    }
      );
    };

    return directive;

});

Scope inheritance is normally straightforward, and you often don't even need to know it is happening... until you try 2-way data binding (i.e., form elements, ng-model) to a primitive (e.g., number, string, boolean) defined on the parent scope from inside the child scope. It doesn't work the way most people expect it should work. What happens is that the child scope gets its own property that hides/shadows the parent property of the same name. This is not something AngularJS is doing – this is how JavaScript prototypal inheritance works.

For more information about prototypical inheritance, see AngularJS Wiki -- The Nuances of Scope Prototypal Inheritance

The DEMO on PLNKR.