指令中未收到广播

Broadcast not received in directive

我的 <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 with a:

$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> link 函数中接收 $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。

更新:


我认为可能的原因是范围不是 'ready'。

在我来自 MainController 的原始 broadcast 中,如果我在 setTime 输出后执行另一个,所有 .on 都会收到:

主控制器:

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

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

来自Documentation:

$broadcast(name, args);

Dispatches an event name downwards to all child scopes (and their children) notifying the registered $rootScope.Scope listeners.

在你的指令中,你没有创建新的范围,我猜你只是在与你的 MainController 相同的范围级别。在这种情况下,您不在 MainController 的 childScope 中,因此无法在那里触发事件。我会尝试以下其中一项:

  1. 始终通过 $rootScope.$broadcast 广播您的活动。所有其他范围都是 $rootScope 的子级,因此无论您在何处使用 $scope.$on 注册一个事件,您都会收到它。您可能还对Why do we use $rootScope.$broadcast in AngularJS?

  2. 感兴趣
  3. 给你的指令一个孤立的$scope。这将充当 MainController 的 childScope,并且应该也能正常工作。 Isolationg the $scope of a directive.

  4. 除了选项 1. 之外,您还可以将 $rootScope.$emit$rootScope.$on 一起使用。有关更多信息,请阅读 $rootScope.$broadcast vs. $scope.$emit

我总是选择 1. 选项,因为有时您不希望指令具有独立的范围。

存在竞争条件。

myDirective控制器和post-link函数在MainController之后执行,监听器在shoppingCartReady事件触发后设置。

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

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

将控制器代码包装成零 $timeout 也会 postpone 代码

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

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

处理此问题的替代方法取决于 shoppingCartReady 事件的内容,但在当前情况下它是多余的:它已经在执行子控制器时发生,他们可以安全地假设 'shopping cart is ready'.

本主题的推荐读物:Directive Controller And Link Timing In AngularJS .