我正在努力理解模型的范围及其对范围有限的指令的约束。
我认为限制指令的范围意味着控制器。$ scope和directive.scope不再是同一个东西。但是,我对如何在指令模板或html中放置模型影响数据绑定感到困惑。我觉得我错过了一些非常基本的东西,继续前进我需要理解这一点。
采用以下代码(在此处小提琴:http://jsfiddle.net/2ams6/)
的JavaScript
var app = angular.module('app',[]);
app.controller('Ctrl',function($scope){
});
app.directive('testel', function(){
return {
restrict: 'E',
scope: {
title: '@'
},
transclude: true,
template: '<div ng-transclude>'+
'<h3>Template title: {{title}}</h3>' +
'<h3>Template data.title:{{data.title}}</h3>' +
'</div>'
}
});
HTML
<div ng-app='app'>
<div ng-controller="Ctrl">
<input ng-model="data.title">
<testel title="{{data.title}}">
<h3>Transclude title:{{title}}</span></h3>
<h3>Transclude data.title:{{data.title}}</h3>
</testel>
</div>
</div>
模型仅更新模板中的{{title}}
,并在翻译中更新{{data.title}}
。 为什么不在转换中{{title}}
或在模板中{{data.title}}
?
将输入移动到翻译中,如此(在此处小提琴:http://jsfiddle.net/eV8q8/1/):
<div ng-controller="Ctrl">
<testel title="{{data.title}}">
<input ng-model="data.title">
<h3>Transclude title: <span style="color:red">{{title}}</span></h3>
<h3>Transclude data.title: <span style="color:red">{{data.title}}</span></h3>
</testel>
</div>
现在意味着只有转化{{data:title}}
才会更新。 为什么不选择模板{{title}}
或{{data.title}}
,也不转换{{title}}
?
最后,将输入移动到模板中,就像这样(在这里小提琴:http://jsfiddle.net/4ngmf/2/):
template: '<div ng-transclude>' +
'<input ng-model="data.title" />' +
'<h3>Template title: {{title}}</h3>' +
'<h3>Template data.title: {{data.title}}</h3>' +
'</div>'
现在意味着只有模板{{data.title}}
得到更新。 同样,为什么不是其他3个绑定?
我希望有一些明显的东西让我盯着我,我想念它。如果你让我得到这个,我会给你买啤酒,或给你一些积分,或其他一些这样的东西。非常感谢。
答案 0 :(得分:113)
你的小提琴创造了三个范围:
Ctrl
关联的范围,因为ng-controller
transclude: true
,scope: { ... }
在fiddle1中,在我们在文本框中输入任何内容之前,我们有以下内容:
范围003是与控制器关联的范围。由于我们尚未输入文本框,因此没有data
属性。在隔离范围004中,我们看到创建了title
属性,但它是空的。它是空的,因为父作用域还没有data.title
属性。
在文本框中输入my title
之后,我们现在有了:
控制器范围003现在有一个新的data
对象属性(这就是它为黄色的原因),其title
属性现在设置为my title
。由于隔离范围属性title
是单向数据绑定到内插值data.title
,因此它也会获得值my title
(该值因为更改而变为黄色。)
转换范围原型继承自控制器范围,因此在转换HTML中,angular可以跟随原型链并在父范围中找到$scope.data.title
(但$scope.title
不存在)。
隔离范围只能访问自己的属性,因此只能访问属性title
。
在小提琴2中,在输入之前我们有与fiddle1相同的图片。
输入my title
后:
注意新data.title
属性出现的位置 - 在转换范围内。隔离范围仍在控制器作用域上查找data.title
,但这次不存在,因此其title
属性值保持为空。
在小提琴3中,在输入之前我们有与fiddle1相同的图片。
输入my title
后:
注意新data.title
属性出现的位置 - 在隔离范围上。其他任何范围都不能访问隔离范围,因此字符串my title
不会出现在其他任何位置。
Angular v1.2的更新:
随着更改eed299a Angular现在会在转化之前清除转换点,因此Template title: ...
和Template data.title: ...
部分不会显示,除非您修改模板ng-transclude
本身就是:
'<h3>Template title: <span style="color:red">{{title}}</span></h3>' +
'<h3>Template data.title: <span style="color:red">{{data.title}}</span></h3>' +
'<div ng-transclude></div>'
在Angular v1.3的以下更新中,进行了此模板更改。
Angular v1.3 +的更新:
自Angular v1.3起,transcluded范围现在是指令的隔离范围的子代,而不是控制器范围的子代。所以在fiddle1中,在我们输入任何内容之前:
此更新中的图片是使用Peri$scope工具绘制的,因此图片略有不同。 @
表示我们有一个使用@
语法的隔离范围属性,粉红色背景意味着该工具无法找到映射的祖先引用(这是真的,因为我们没有' t输入文本框中的任何内容。)
在文本框中输入my title
之后,我们现在有了:
使用@
绑定的隔离属性将始终在@
符号后的隔离范围中显示插值字符串结果。 Peri $ scope也能够在祖先范围内找到这个确切的字符串值,因此它还显示了对该属性的引用。
在小提琴2中,在输入之前我们有与fiddle1相同的图片。
输入my title
后:
注意新data.title
属性出现的位置 - 在转换范围内。隔离范围仍在控制器作用域上查找data.title
,但这次不存在,因此其title
属性值保持为空。
在小提琴3中,在输入之前我们有与fiddle1相同的图片。
输入my title
后:
注意新data.title
属性出现的位置 - 在隔离范围上。即使被转换的范围可以通过$parent
关系访问隔离范围,它也不会查找title
或data.title
- 它只会查看控制器范围(即,它将遵循原型继承),并且控制器范围没有定义这些属性。
答案 1 :(得分:22)
在阅读了所有提出的答案后,包括马克的精彩原理图,这是我对范围的理解,也是我对问题的继承。我希望评论这个图表的位置,以便我可以适当更新。我希望它只是对马克所呈现的内容提供了不同的观点:
答案 2 :(得分:8)
好问,顺便问一下!希望我的回答是雄辩的......
答案与被饶恕的元素如何获得其范围有关。
总结一下,你有两个范围:
$scope.data.title
。 (由input
元素隐式添加)$scope.title
。当您更改控制器的$scope.data.title
时,指令的$scope.title
也会发生变化。
您还有两个HTML部分,即被转换的模板和模板。发生的事情是,被转换的HTML位于控制器的范围内,而模板HTML位于指令的范围内。因此,转化的HTML对title
一无所知,模板范围对data.title
这实际上就是Transclusion的目的 - 允许指令的子元素保持其父范围,在这种情况下是控制器的范围。根据设计,被转换的元素不知道它们在指令中,因此无法访问指令的范围。
另一方面,指令模板只能访问指令的范围。
我已经改变了一些代码,使名称更清晰(但功能相同)