简体   繁体   中英

AngularJS Directive to directive communication

I've a directive nested within another directive as in the below fiddle.

http://jsfiddle.net/sriramr/T7W6T/3/

My question is: if a variable in the parent directive changes value, how to automatically update the value of a variable in the child directive which is computed from the parent variable?

var myapp = angular.module('myApp',[]);
myapp.directive('parentDir', parentDir);
    function parentDir() {
        return {
            restrict:'E',
            controller: function eCtrl($scope) {
                $scope.parVal = 100;
                $scope.$on("event",function(e,data) {
                    console.log("emit")
                    $scope.parVal = 200;
                })

            },
            template:'<div><first-dir></first-dir</div>'
        }
    }

myapp.directive('firstDir', firstDir);
function firstDir() {
    return {
        restrict:'E',
        controller: function($scope) {
            //$scope.$watch('parVal',function() {
                $scope.childVal = $scope.parVal + 1;
            //})
            $scope.changeVal = function() {
                $scope.$emit("event")
            }
        },
        template:'<div>first Dir: {{parVal}} {{childVal}} <br /> <button ng-click="changeVal()">Change</button></div>'
    }
}

The variable parVal from the parent directive's controller's scope gets handed down to the child directive's controller. The child directive has its own variable childVal which is parVal + 1 . I try to change parVal 's value indirectly by emitting an event in the child directive. As expected, parVal 's value changes and is reflected in the View. However, childVal 's value is not changed.

I am able to see the updated value of childVal using a $watch on parVal . Is there any other way I can do this?

There are a few ways you can share code between these two directives.

One way is to take advantage of how firstDir prototypically inherits from parentDir . You're already doing that with parVal , but you probably had issues updating parVal from within the child directive. An easy workaround is to create an update function in the parent directive. This gives you access to update the scope directly. example: http://jsfiddle.net/T7W6T/4/
edit: I don't like the above approach because it tightly couples both directives and firstDir won't work on it's own.

Another way is to create a shared service. A service in angular is a singleton, so anywhere it is injected into a controller will be the same instance as everywhere else. You can easily create a pub/sub mechanism. Just be sure to clean up the subscribers when the scope of the subscriber is destroyed. This is my preferred way to share between directives and controllers because you don't pollute your scope. Remember, everything bound to scope has an effect on the digest.

Example code of a minimal pub/sub mechanism:

myapp.service('SharedService', function(){
    var listeners = [];
    return {
        publish: function(){
            angular.forEach(listeners, function(listener){
               listener.call(null); 
            });
        },
        subscribe: function(fn){
            listeners.push(fn);
        },
        unsubscribe: function(fn){
            var idx = listeners.indexOf(fn);
            if(idx > -1){
                 listeners.splice(idx,1);   
            }
        }
    }
});

You interact with this from the parent directive like so:

            var update = function(){
                $scope.parVal = 200;
            };

            SharedService.subscribe(update);

            $scope.$on("$destroy", function(){
               SharedService.unsubscribe(update); 
            });

And the child directive is the only thing that can access the function to publish to listeners:

        $scope.updateParVal = function(){
            SharedService.publish();
        };

http://jsfiddle.net/T7W6T/5/

There's a pretty good explanation on SO about whether scope inheritance or $emit is better: https://stackoverflow.com/a/18179640/151445

One thing I don't usually see mentioned about the service approach is that you control exactly where subscribers and publishers are bound. With $scope.$emit and $scope.$on , anyone with a scope can go crazy with events.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM