所有
假设我有两个指令(dir1和dir2),它们都是隔离的范围。从一些帖子中,我了解到我需要使用"要求"获得另一个指令的范围,但有一个问题让我很困惑:
假设我使用ng-repeat生成了很多dir1和dir2,我怎么知道某些dir1,需要哪个dir2的控制器范围(cos有很多dir2,在我的理解中,所有这些范围在dir2控制器中彼此独立)?
例如:
app.directive("dir1", function(){
var counter = 0;
return {
restrict:"AE",
scope:{},
template: "<button class='dir1_btn'>highlight dir2_"+(couter++)+" </button>",
link:function(scope, EL, attrs){
EL.find("button.dir1_btn").on("click", function(){
// How to let according dir2 know this click?
})
}
}
})
app.directive("dir2", function(){
var counter = 0;
return {
restrict:"AE",
scope:{},
template: "<span class='dir2_area'>This is dir2_"+(couter++)+" </span>",
link:function(scope, EL, attrs){
// Maybe put something here to listening the event passed from dir1?
}
}
})
和html一样(为了简单的目的,我只在其中放了两个,实际上它将由ng-repeat生成):
<dir1></dir1>
<dir2></dir2>
<dir1></dir1>
<dir2></dir2>
考虑到这就像开关和灯一样,dir1是根据灯光(dir2)打开(通过改变背景颜色)的开关。
在实际项目中,我想做的是angularJS指令版本 sidemenu和scrollContent,sidemenu中的每个项目都是一个指令, 单击它将根据内容(另一个指令)自动滚动 顶部。
我想知道该怎么做?我知道这在jQuery中很容易,只是想知道如何将它挂钩到AngularJS数据驱动模式中。
由于
答案 0 :(得分:1)
您可能必须使用某种策略。某种标识符挂钩。很明显,你不能使用require(要求指令的控制器,你也没有任何东西,它只能查看祖先或本身而不是兄弟姐妹)。例如,您可以添加id
属性和for
属性,并使用基于特定属性值的选择来定位元素并触发事件。这个相关元素的位置并不重要。
你的指令可能如下:
<dir1 dir-for="id1"></dir1>
<dir2 dir-id="id1"></dir2>
<dir1 dir-for="id2"></dir1>
<dir2 dir-id="id2"></dir2>
简单的实施:
.directive("dir1", function($document) {
var counter = 0;
return {
restrict: "AE",
scope: {
dirFor: '@'
},
template: "<button class='dir1_btn' ng-click='handleClick()'>highlight dir2_({{dirFor}}) </button>",
link: function(scope, EL, attrs) {
var $target = angular.element(
$document[0].querySelector('[dir-id="' + scope.dirFor + '"]'))
.contents().scope();
var clicked = false;
scope.handleClick = function() {
clicked = !clicked;
targetScope.$broadcast("SWITCH_CLICKED", clicked);
}
scope.$on('$destory',function() {
$target = null;
}
}
}
})
app.directive("dir2", function() {
var counter = 0;
return {
restrict: "AE",
scope: {
dirId: '@'
},
template: "<span class='dir2_area' ng-class=\"{true:'on', false:'off'}[status]\">This is dir2_{{dirId}}</span>",
link: function(scope, EL, attrs) {
console.log(scope.$id);
scope.status = false;
scope.$on('SWITCH_CLICKED', function(e, data) {
scope.status = data;
});
}
}
});
<强>演示强>
var app = angular.module('app', []).controller('ctrl', angular.noop);
app.directive("dir1", function($document) {
var counter = 0;
return {
restrict: "AE",
scope: {
dirFor: '@'
},
template: "<button class='dir1_btn' ng-click='handleClick()'>highlight dir2_({{dirFor}}) </button>",
link: function(scope, EL, attrs) {
var $target = angular.element($document[0].querySelector('[dir-id="' + scope.dirFor + '"]')).contents();
var clicked = false;
scope.handleClick = function() {
clicked = !clicked;
$target.scope().$broadcast("SWITCH_CLICKED", clicked);
}
scope.$on('$destroy',function() {
$target = null;
});
}
}
})
app.directive("dir2", function() {
var counter = 0;
return {
restrict: "AE",
scope: {
dirId: '@'
},
template: "<span class='dir2_area' ng-class=\"{true:'on', false:'off'}[status]\">This is dir2_{{dirId}}</span>",
link: function(scope, EL, attrs) {
scope.status = false;
scope.$on('SWITCH_CLICKED', function(e, data) {
scope.status = data;
});
}
}
})
&#13;
.on{
color:green;
}
.off{
color:blue;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<dir1 dir-for="id1"></dir1>
<dir2 dir-id="id1"></dir2>
<dir1 dir-for="id2"></dir1>
<dir2 dir-id="id2"></dir2>
</div>
&#13;
我已经使用$document[0].querySelector('[dir-id="' + scope.dirFor + '"]')).contents().scope()
来获取范围,同样您也可以.controller
来获取控制器实例。当前的例子是进行绝对选择(使用文档),你也可以使它相对。
答案 1 :(得分:1)
这里要注意的最重要的事情是我认为你想使用ng-class因为你在ng-repeat中创建了两个指令,我假设你正在迭代一个对象列表(即使它们是两个单独的ng-repeats,如果你遍历同一个对象列表,它将起作用.JQuery不应该是必要的)?将ngClass对象附加到迭代的每个对象,将其放在dir2中的ng-class
属性上,然后给dir1访问权限以进行更改。如果要为过渡设置动画,ngClass会提供动画钩子。我的其余部分可能会有所帮助,但我想重做它,因为我想到了ng-class。我现在必须回去工作了。我会留意反馈,如果您有疑问,请尽快回答。
我认为可能有几种方法可以更好地完成你想要做的事情。目前尚不清楚为什么两个指令都需要具有隔离范围。当我使用更多角度时,我发现虽然隔离范围是一种强大的技术,但最好避免过度使用它。
对于require
指令属性,此帖explains how to make directives communicate via their controllers非常好。
我有两个可能的建议给你。 制定一个指令 为什么你不能把模板合二为一?
或者,如果我认为他们需要分开的某些原因,你可以考虑在他们之间共享一个对象。
<div ng-repeat='obj in sharedDirObjs'>
<dir1 shared-dir-obj='obj'></dir1>
<dir2 shared-dir-obj='obj'></dir2>
</div>
app.controller('ctrl', function() {
$scope.sharedDirObjs = [obj1, obj2, obj3]
});
app.directive("dir1", function(){
var counter = 0;
return {
restrict:"AE",
scope:{sharedDirObj : '='},
template: "<button class='dir1_btn' ng-click='clickFn()'>highlight dir2_"+(couter++)+" </button>",
link:function(scope, EL, attrs){
var dir1vars...
scope.clickFn = function(){
// dir1 logic...
scope.sharedDirObj.dir2.clickFn(dir1vars...);
};
}
}})
app.directive("dir2", function(){
var counter = 0;
return {
restrict:"AE",
scope:{sharedDirObj : '='},
template: "<span class='dir2_area'>This is dir2_"+(couter++)+" </span>",
link:function(scope, EL, attrs){
scope.sharedDirObj.dir2 = {};
scope.sharedDirObj.dir2.clickFn(dir1vars...) {
// access to dir2 vars
};
}
}})
类似地,您可以创建一个服务,该服务包含通过注入服务共享的对象数组,并使用ng-repeat中的$ index索引,或者您可以使用PSL建议的id系统。请注意,我上面描述的解决方案可以使用隔离范围,或者没有使用scope.$eval(attr.sharedObj);
在您的任何一个或两个指令上。这个问题的答案provides a solid runthrough of when and why to use isolated scope.在任何情况下,如上所示,最好不要通过共享对象来管道函数,并且需要处理时序问题。更好的方法是在对象上存储属性并设置范围。$在你的dir2中观察它们。