混淆了Angularjs跨越和隔离范围和绑定
我很难理解范围有限的指令范围及其约束力。
我得到的限制在一个指令的范围意味着控制器。$ 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}}
?
将input移动到像这样的跨越(在这里摆弄: 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>
现在意味着只有transclude {{data:title}}
得到更新。 为什么不是模板{{title}}
或{{data.title}}
,也不是{{data.title}}
{{title}}
?
最后,将input移动到模板内,像这样(在这里提琴: 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个绑定?
我希望有一些明显的盯着我,我很想念它。 如果你让我得到这个,我会给你买一瓶啤酒,或者给你一些点数,或者其他的一些东西。 非常感谢。
你的小提琴创造了三个范围:
- 由于
ng-controller
,与控制器Ctrl
相关的范围 - 一个指令transcluded作用域,因为
transclude: true
- 一个指令隔离范围,由于
scope: { ... }
在小提琴1中,在我们input任何文字之前,我们有以下几点:
范围003是与控制器相关的范围。 由于我们尚未input文本框,因此没有data
属性。 在隔离范围004中,我们看到创build了一个title
属性,但是它是空的。 它是空的,因为父范围还没有data.title
属性。
在文本框中inputmy title
后,我们现在有:
控制器作用域003现在有一个新的data
对象属性(这就是为什么它是黄色的),它的title
属性现在设置为my title
。 由于隔离作用域属性title
是单向数据绑定到data.title
的插值,所以它也得到my title
的值(因为它已经改变,所以这个值是黄色的)。
transcluded作用域原型从控制器作用域inheritance,因此在$scope.data.title
HTML中,angular可以遵循原型链,并在父作用域中find$scope.data.title
(但$scope.title
在那里不存在)。
隔离范围只能访问自己的属性,因此只有属性title
。
在fiddle2中,在打字前我们有和fiddle1一样的图片。
inputmy title
:
注意新的data.title
属性出现在data.title
作用域上。 隔离作用域仍然在控制器作用域上查找data.title
,但是这次没有,所以它的title
属性值保持为空。
在小提琴3中,在打字之前,我们有和fiddle1一样的照片。
inputmy title
:
注意新的data.title
属性出现在隔离范围内。 其他范围都没有访问隔离范围,所以stringmy title
不会出现在其他地方。
更新Angular v1.2:
随着改变eed299a Angular现在清除transcluding之前的transclusion点,所以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作用域现在是该指令的隔离作用域的子项,而不是控制器作用域的子项。 所以在小提琴1中,在我们input任何东西之前:
这个更新中的图片是用Peri $ scope工具绘制的,所以图片有点不一样。 @
表示我们有一个使用@
语法的隔离作用域属性,粉红色的背景表示该工具无法find映射的祖先引用(这是真的,因为我们没有input任何东西到文本框)。
在文本框中inputmy title
后,我们现在有:
使用@
绑定的隔离属性将始终在@
符号之后的隔离范围中显示插入的string结果。 Peri $ scope也能够在祖先范围内find这个确切的string值,所以它也显示了对该属性的引用。
在小提琴2中,在打字之前,我们有和fiddle1一样的照片。
inputmy title
:
注意新的data.title
属性出现在data.title
作用域上。 隔离作用域仍然在控制器作用域上查找data.title
,但是这次没有,所以它的title
属性值保持为空。
在小提琴3中,在打字之前,我们有和fiddle1一样的照片。
inputmy title
:
注意新的data.title
属性出现在隔离范围内。 即使data.title
作用域可以通过$parent
关系访问隔离作用域,但它不会在那里查找title
或data.title
– 它只会查看控制器作用域(即它将遵循原型inheritance),而控制器作用域没有定义这些属性。
读完所有的答案,包括马克的奇妙的图表,这是我对范围的理解,它是我的问题的inheritance。 我将不胜感激评论这个图下降,以便我可以适当更新。 我希望这只是提供了一个不同的观点,马克提出:
那么问,顺便说一句! 希望我的回答是雄辩的。
答案与如何横穿的元素得到他们的范围。
总而言之,你有两个范围:
- 控制器的范围,其中有
$scope.data.title
。 (通过您的input
元素隐式添加) - 指令的作用域,其中有
$scope.title
。
当你改变控制器的$scope.data.title
,指令的$scope.title
也会改变。
你也有两段HTML,transcluded和模板。 所发生的事情就是HTML被包含在控制器的范围之内,并且HTML模板在指令的范围之内。 所以被包含的HTML不知道关于title
任何内容,而模板范围对data.title
没有任何了解
这实际上就是Transclusion的目的 – 允许一个指令的子元素保留他们的父范围 ,在这个例子中是控制器的范围。 通过devise,transcluded元素不知道他们在一个指令,所以没有访问指令的范围。
另一方面,指令模板只能访问指令的范围。
我已经改变了你的代码,使名称更清晰一些(虽然function相同)