3

我的,之间有父子控制器关系<main>,因此:<div><my-directive>

<main ng-controller="MainController">

    <nav>
        <ul>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
        </ul>
    </nav>

    <div ng-controller="AboutController">

    </div>

    <my-directive></my-directive>

</main>

在 MainController 中,我使用以下命令执行 $broadcast:

$scope.$broadcast('shoppingCartReady', msg);

在 AboutController 中,我可以通过以下方式成功接收此 $broadcast:

angular.module('aboutModule', [])
    .controller('AboutController', require('./about/aboutController'));

var AboutController = function ($scope, $rootScope) {

    $scope.$on('shoppingCartReady', function(event, msg){
        console.log(msg);
    });

};

module.exports = [ '$scope', '$rootScope', AboutController];

但是,当尝试在<my-directive>链接函数中接收 $broadcast 时,似乎永远不会收到:

angular.module('shopModule', [])
    .directive('shopModuleDirective', require('./shopModuleDirective'))
    .directive('myDirective', require('./myDirective'));

var myDirective = function ($rootScope) {

    function link($scope, element, attrs, baseCtrl) {

        $scope.$on('shoppingCartReady', function (event, msg) {
            console.log(msg);
        });
    }

    return {
        restrict: 'E',
        require: '^shopModuleDirective',
        link: link
    };
};

return ['$rootScope', myDirective];

更新


我什至在我的指令中创建了一个控制器:

angular.module('shopModule', [])
    .directive('shopModuleDirective', require('./shopModuleDirective'))
    .directive('myDirective', require('./myDirective'));

var myDirective = function ($rootScope) {

    var controller = ["$scope", "$element", function ($scope, element) {
        console.log('waiting for .on....');
        $scope.$on('shoppingCartReady', function (event, cache) {
             console.log('shoppingCartReady .on rcvd!');
        });
    }]

    function link($scope, element, attrs, baseCtrl) {

        $scope.$on('shoppingCartReady', function (event, msg) {
            console.log(msg);
        });
    }

    return {
        restrict: 'E',
        require: '^shopModuleDirective',
        link: link
    };
};

return ['$rootScope', myDirective];

我可以看到日志

console.log('waiting for .on....');

但是 .on 从未收到。

更新:


我认为可能的原因是由于范围没有“准备好”。

在我来自 MainController 的原始文件中,如果我在outbroadcast之后执行另一个,则会收到所有内容:setTime.on

主控制器:

$scope.$broadcast('shoppingCartReady', msg);

setTimeout(function(){
    $scope.$broadcast('shoppingCartReady', msg);
}, 8000);
4

2 回答 2

4

文档

$广播(名称,参数);

向下调度事件名称到所有子作用域(及其子作用域),通知已注册的 $rootScope.Scope 侦听器。

在您的指令中,您没有创建新范围,我猜您与您的MainController. 在这种情况下,您不在 childScope 中,MainController因此无法在那里触发事件。我会尝试以下方法之一:

  1. 始终通过 广播您的活动$rootScope.$broadcast。所有其他范围都是子范围$rootScope,因此无论您使用 注册事件$scope.$on,您都会收到它。您可能还对我们为什么在 AngularJS 中使用 $rootScope.$broadcast 感兴趣?

  2. 给你的指令一个孤立的$scope. 这将作为 childScopeMainController并且应该也可以工作。隔离指令的 $scope

  3. 除了选项之外,1.您还可以$rootScope.$emit$rootScope.$on. 有关更多信息,请阅读$rootScope.$broadcast 与 $scope.$emit

我总是选择选项1.,因为有时你不希望你的指令有一个孤立的范围。

于 2016-04-27T07:38:15.080 回答
3

有一个竞争条件。

myDirectivecontroller 和 post-link 函数在 之后执行,并且在事件触发MainController后设置侦听器。shoppingCartReady

一个好的、可测试的指令设计的经验法则是将所有与范围相关的逻辑保留在控制器中,链接函数和$onInit钩子完全用于应该在那里而不是其他任何地方发生的事情,比如对编译的 DOM 内容的操作。

不太明显但独特的用例link是理想的执行顺序(后链接函数以相反的顺序执行,从子级到父级)。如果MainController成为指令,并且scope.$broadcast('shoppingCartReady', msg)link函数而不是控制器中执行,这保证了正确的执行顺序。

将控制器代码包装为零$timeout也会推迟代码

$timeout(function(){
    $scope.$broadcast('shoppingCartReady', msg);
});

在子指令中链接函数后执行,但也会指定一些代码气味。这就是为什么范围事件是不太理想的指令通信方式并且容易成为反模式的原因之一。

处理这种情况的另一种方法取决于shoppingCartReady事件是关于什么的,但在当前情况下它是多余的:它在子控制器执行的那一刻已经发生,他们可以安全地假设“购物车已准备好”。

推荐阅读本主题:Directive Controller And Link Timing In AngularJS

于 2016-04-27T14:13:30.373 回答