问题描述
我的 、
之间有父子控制器关系像这样:<导航><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 .
这篇关于指令中未收到广播的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!