Angularjs 如何在角度指令之间进行有效沟通?
我遇到了我的应用程序所需的冗余逻辑,我希望将其转换为一种指令形式,在这种形式下,我不会将控制器作用域与视图属性进行卷积。这个想法很简单。我想要两个指令(一个父元素和一个子元素),具有1对多关系(一个父元素有X个子元素) 该指令只是一个列表,用户可以在其中单击一个元素(子指令),并让该元素添加一个Angularjs 如何在角度指令之间进行有效沟通?,angularjs,Angularjs,我遇到了我的应用程序所需的冗余逻辑,我希望将其转换为一种指令形式,在这种形式下,我不会将控制器作用域与视图属性进行卷积。这个想法很简单。我想要两个指令(一个父元素和一个子元素),具有1对多关系(一个父元素有X个子元素) 该指令只是一个列表,用户可以在其中单击一个元素(子指令),并让该元素添加一个活动类,而所有其他同级元素都删除了活动类 控件基本上是一个单选按钮(功能相同),我只是想让它对任何类型的元素都通用。这就是我到目前为止所做的: app.directive('skSelect', func
活动
类,而所有其他同级元素都删除了活动
类
控件基本上是一个单选按钮(功能相同),我只是想让它对任何类型的元素都通用。这就是我到目前为止所做的:
app.directive('skSelect', function(){
return {
restrict:'A',
controller: function($scope){
this.reset = function(){
//HERE I WANT TO SET ALL CHILDREN sk-select-item DIRECTIVES TO isSelected = false SOMEHOW
}
},
link: function(scope, element, attrs){
}
}
});
app.directive('skSelectItem', function(){
return {
restrict:'A',
require:'^skSelect',
replace:false,
template:'<div ng-class="{active: isSelected}" ng-click="select()"></div>',
link:function(scope, element, attrs, ctrl){
scope.isSelected = false;
//scope.$watch('isSelected', function(isSelected){
// if(isSelected){
// element.addClass('active');
// }else{
// element.removeClass('active');
// }
//});
scope.select = function(){
ctrl.reset();
scope.isSelected = true;
}
}
}
});
app.directive('skSelect',function(){
返回{
限制:'A',
控制器:功能($scope){
this.reset=函数(){
//在这里,我想将所有子项sk select item指令设置为isSelected=false
}
},
链接:函数(范围、元素、属性){
}
}
});
app.directive('skSelectItem',function(){
返回{
限制:'A',
要求:“^skSelect”,
替换:false,
模板:“”,
链接:函数(范围、元素、属性、ctrl){
scope.isSelected=false;
//范围:$watch('isSelected',函数(isSelected){
//如果(当选){
//元素addClass('active');
//}其他{
//元素。removeClass(“活动”);
// }
//});
scope.select=函数(){
ctrl.reset();
scope.isSelected=true;
}
}
}
});
因此,我的问题在于尝试使用一个
reset()
函数,在该函数中,父对象需要与子对象通信,以将其isSelected属性设置为false
。我也不确定是否应该在skSelectItem
指令中使用模板
,以添加/删除活动的
类并绑定单击事件,或者是否应该只使用元素。on('click')
和范围。$watch('isSelected',…)
为了实现这一点?有几种方法可以处理两个指令之间的通信。下面是两个很好的示例,说明如何实现这一点
一般关注事项
在指令定义上,如果您使用的是类似于
的模板,则必须将scope属性指定为true,才能为。否则,您将在父作用域上共享该变量
使用$broadcast$on
在这种情况下,父指令可以发送一个事件来通知子指令某些内容发生了更改
在代码中:
// on the parent directive.
this.reset = function() {
$scope.$broadcast('skSelect::reset');
}
//on the child directive. remember to set the scope to true.
link:function(scope, element, attrs, ctrl){
scope.$on('skSelect::reset', function (event) {
scope.isSelected = false;
});
这是标准的解决方案,但在使用相同类型的嵌套指令时会出现一些问题。由于无法停止emit事件,因此父级上的am事件抛出由所有子指令侦听
要解决这个问题,您应该生成一个随机键,用于事件的名称
function buildEventName (key) {
return 'skSelect::reset' + key;
}
// parent controller
controller: function($scope){
this.eventKey = Math.random() * 999999; // random key here.
this.reset = function() {
$scope.$emit(buildEventName(this.eventKey));
}
},
//子链接函数
link:function(scope, element, attrs, ctrl){
scope.$on(buildEventName(ctrl.eventKey), function (event) {
scope.isSelected = false;
});
在父控制器上保存子作用域
您应该尝试使用scope.$emit,并将子指令订阅到s向父级抛出的事件。我将在一分钟后发布一个答案。好的,让父$emit一个事件,让子$emit一个事件,并在事件发生时设置
isSelected=false
?对我来说这听起来很可靠。使用模板怎么样?我想能够在我正在写的任何类型的元素上使用它,给我一分钟。好的,这是有意义的。非常感谢。顺便说一句,我认为我们需要使用$scope.$broadcast()
而不是$scope.$emit()
,以便向下传播事件(父级->子级)。除此之外,它工作得很好!
// parent controller
controller: function($scope){
var childs = [];
this.reset = function() {
angular.forEach(childs, function (child) {
child.clear();
});
};
this.addChild = function (childScope) {
childs.push(childScope);
};
},
// child link function
link:function(scope, element, attrs, ctrl){
ctrl.addChild(scope);
scope.clear = function () {
scope.isSelected = false;
};
scope.select = function(){
ctrl.reset();
scope.isSelected = true;
};
}