指令中未收到广播 [英] Broadcast not received in directive

查看:27
本文介绍了指令中未收到广播的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的

之间有父子控制器关系像这样:

<导航><ul><li>1</li><li>2</li><li>3</li><li>4</li></nav><div ng-controller="关于控制器">

<我的指令></我的指令></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){控制台日志(味精);});};module.exports = [ '$scope', '$rootScope', AboutController];

然而,当试图在 <my-directive> 链接函数中接收 $broadcast 时,它似乎永远不会收到:

angular.module('shopModule', []).directive('shopModuleDirective', require('./shopModuleDirective')).directive('myDirective', require('./myDirective'));var myDirective = 函数($rootScope){功能链接($scope,元素,属性,baseCtrl){$scope.$on('shoppingCartReady', function (event, msg) {控制台日志(味精);});}返回 {限制:'E',要求:'^shopModuleDirective',链接:链接};};返回 ['$rootScope', myDirective];

更新

<小时>

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

angular.module('shopModule', []).directive('shopModuleDirective', require('./shopModuleDirective')).directive('myDirective', require('./myDirective'));var myDirective = 函数($rootScope){var controller = ["$scope", "$element", function ($scope, element) {console.log('等待 .on....');$scope.$on('shoppingCartReady', function (event, cache) {console.log('shoppingCartReady .on rcvd!');});}]功能链接($scope,元素,属性,baseCtrl){$scope.$on('shoppingCartReady', function (event, msg) {控制台日志(味精);});}返回 {限制:'E',要求:'^shopModuleDirective',链接:链接};};返回 ['$rootScope', myDirective];

我可以看到日志

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

但从未收到 .on.

更新:

<小时>

我认为可能的原因是范围没有准备好".

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

主控制器:

$scope.$broadcast('shoppingCartReady', msg);设置超时(功能(){$scope.$broadcast('shoppingCartReady', msg);}, 8000);

解决方案

存在竞争条件.

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

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

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

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

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

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

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

该主题的建议阅读:AngularJS 中的指令控制器和链接时序 .

I have a parent-child controller relationship between my <main>, <div> and <my-directive> as such:

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

Within the MainController, i perform a $broadcast with a:

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

Within AboutController, i can successfully receieve this $broadcast via:

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];

However, when trying to receive the $broadcast within <my-directive> link function, it seems to never be received:

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];

UPDATE


I have even created a controller within my directive:

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];

I can see the log for

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

But the .on is never received.

UPDATE:


I think the possible cause is due to scope's not being 'ready'.

Within my original broadcast from MainController, if i perform another after a setTime out, all .on are received:

MainController:

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

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

解决方案

There is a race condition.

myDirective controller and post-link function are executed after MainController, and the listener is set up after shoppingCartReady event has been triggered.

A rule of thumb for good, testable directive design is to keep all scope-related logic in controller, linking functions and $onInit hook are used exactly for the things that should happen there and not anywhere else, like manipulations on compiled DOM content.

Less obvious but distinctive use case for link is the desirable order of execution (post-linking functions are executed in reverse order, from children to parent). If MainController becomes a directive, and scope.$broadcast('shoppingCartReady', msg) is executed in link function and not controller, this guarantees the proper order of execution.

Wrapping controller code into zero $timeout will also postpone the code

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

to be executed after linking functions in children directives, but will also designate some code smell. This is one of the reasons why scope events are less desirable ways of directive communication and are prone to be anti-patterns.

The alternative way of handling this depends on what shoppingCartReady event is about, but in current case it is redundant: it has already happened at the moment when children controllers are executed, they can safely assume that 'shopping cart is ready'.

A suggested reading for this topic: Directive Controller And Link Timing In AngularJS .

这篇关于指令中未收到广播的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆