AngularJS指令指令通信

时间:2014-06-26 01:23:44

标签: javascript angularjs angularjs-directive angularjs-scope

我有一个嵌套在另一个指令中的指令,如下面的小提琴。

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

我的问题是:如果父指令中的变量改变了值,如何自动更新子指令中从父变量计算的变量值?

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>'
    }
}

来自父指令控制器范围的变量parVal将传递给子指令的控制器。子指令有自己的变量childVal,即parVal + 1。我试图通过在子指令中发出一个事件来间接地改变parVal的值。正如预期的那样,parVal的值会发生变化并反映在视图中。但是,childVal的值不会更改。

我可以在childVal上使用$ watch查看parVal的更新值。还有其他办法吗?

1 个答案:

答案 0 :(得分:1)

有几种方法可以在这两个指令之间共享代码。

一种方法是利用firstDir原型继承自parentDir的方式。您已经使用parVal执行此操作,但您可能无法在子指令中更新parVal。一个简单的解决方法是在父指令中创建更新函数。这使您可以直接更新范围。例如:http://jsfiddle.net/T7W6T/4/
编辑:我不喜欢上述方法,因为它紧密地结合了两个指令,并且firstDir不会对它自己进行处理。

另一种方法是创建共享服务。 angular中的服务是一个单独的服务,因此它注入控制器的任何地方都将是与其他地方相同的实例。您可以轻松创建发布/订阅机制。只要确保在订阅者的范围被破坏时清理订阅者。这是我在指令和控制器之间共享的首选方式,因为您不会污染范围。请记住,与范围绑定的所有内容都会对摘要产生影响。

最小pub / sub机制的示例代码:

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);   
            }
        }
    }
});

您可以从父指令进行交互,如下所示:

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

            SharedService.subscribe(update);

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

并且子指令是唯一可以访问函数以发布给侦听器的东西:

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

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

关于范围继承或$emit是否更好,对SO有一个很好的解释:https://stackoverflow.com/a/18179640/151445

我通常看到的有关服务方法的一件事是您可以准确控制订阅者和发布者的约束位置。对于$scope.$emit$scope.$on,任何拥有范围的人都可以对事件发疯。