我的指令设置如下:
<div data-directive-a data-value="#33ff33" data-checked="true">
<div data-directive-b></div>
</div>
directiveB
呈现。directiveA
有一个复选框,用于在检查时更改某些值。directiveA
和directiveB
的范围内访问。我设法做到这一点,但只能通过引用$$prevSibling
- 有更好的方法吗?
以下是代码:http://jsfiddle.net/janeklb/yugQf/(在此示例中,单击复选框只是为了“清除”值)
-
更深入一点:
directiveA
的'内容'(被转录到其中的内容)并不总是directiveB
。其他类似directiveB
的指令也会在那里结束。 directiveB
“类型”将始终在directiveA
内使用。
答案 0 :(得分:12)
为避免将组件耦合太多,我会避免使用$$prevSibling
。由于directiveB
类组件预计将在directiveA
组件中使用,因此最佳解决方案是使用require
。
.directive( 'directiveB', function () {
return {
require: '^directiveA',
scope: true,
link: function ( scope, element, attrs, directiveA ) {
scope.obj = directiveA.getObj();
}
};
})
^require
表示该指令的元素或DOM层次结构中它上面的任何元素上的某个地方是一个名为directiveA
的指令,我们想在其控制器上调用方法。
.directive( 'directiveA', function () {
return {
// ...
controller: function ( $scope ) {
// ...
this.getObj = function () {
return $scope.obj;
};
}
};
})
现在在directiveB
,您可以使用ng-model="obj.attr"
。
这方面有很多变化,但考虑到问题的一般性,我觉得这是最好的方法。这是一个更新的小提琴:http://jsfiddle.net/yugQf/7/。
答案 1 :(得分:7)
由于
directiveB
类组件预计将在directiveA
个组件中使用,因此最佳解决方案是使用require
。
我一直在玩弄这个,我相信directiveA
上的控制器是唯一的解决方案(所以+1 Josh)。这是使用OP的小提琴的范围:
(反转棕色箭头,你有$$ previousSibling而不是$$ nextSibling。)
除了$$previousSibling
之外,范围004没有隔离范围003的路径。请注意,范围004是directiveA
创建的转换范围,并且directiveB
未创建新范围,此范围也由directiveB
使用。
由于要在directiveB
的控制器中创建要与directiveA
共享的对象,我们也无法使用属性在指令之间共享数据。
在指令中创建模型,然后将该模型共享给外部世界是非常典型的。通常,您需要在指令之外甚至在控制器之外定义模型(listen for a few minutes to Misko)。服务通常是存储模型/数据的好地方。控制器通常应该引用需要投影到与之关联的视图中的模型部分。
为简单起见,我将在控制器上定义模型,然后指令将以正常方式访问此模型。出于教学目的,directiveA
仍将使用隔离范围,而directiveB
将使用scope: new
创建一个新的子范围,如@Josh的答案。但是现在我们在父范围内定义了模型,任何类型(隔离,新子,没有新范围)和组合都可以工作。
<强>控制强>:
$scope.model = {value: '#33ff33', checkedState = true};
<强> HTML 强>:
<div ng-controller="NoTouchPrevSibling">
<div data-directive-a data-value="model.value" data-checked="model.checkedState">
<div data-directive-b></div>
</div>
出于其他教学原因,我选择将directiveA两个模型属性作为单独的属性传递,但也可以传递整个模型/对象。由于directiveB将创建子范围,因此它不需要传递任何属性,因为它可以访问所有父/控制器范围属性。
<强>指令强>:
app.directive('directiveA', function () {
return {
template: '<div>'
+ 'inside parent directive: {{checkedState}}'
+ '<input type="checkbox" ng-model="checkedState" />'
+ '<div ng-transclude></div>'
+ '</div>',
transclude: true,
replace: true,
scope: {
value: '=',
checkedState: '=checked'
},
};
});
app.directive('directiveB', function () {
return {
template: '<div>'
+ '<span>inside transcluded directive: {{model.checkedState}}</span>'
+ '<input type="text" ng-model="model.value" />'
+ '</div>',
replace: true,
scope: true
};
});
<强>作用域强>:
请注意,directiveB的子范围(006)继承自directiveA的transcluded范围(005)。
单击复选框并更改文本框中的值:
请注意,Angular会处理更新隔离范围属性。正常JavaScript prototypal inheritance为directiveB的子范围提供对控制器范围(003)中model
的访问。