对Angularjs的困惑感到困惑并隔离了范围和绑定

dew*_*ewd 55 angularjs angularjs-directive angularjs-scope

我正在努力理解模型的范围及其对范围有限的指令的约束.

我认为限制指令的范围意味着控制器.$ 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>'
    }    
}); 
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

模型仅{{title}}在模板内和翻译{{data.title}}中更新.为什么不在翻译{{title}}中也不{{data.title}}在模板中?

将输入移动到translude中就像这样(在这里小提琴: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>
Run Code Online (Sandbox Code Playgroud)

现在意味着只有transclude {{data:title}}才会更新.为什么不要么模板{{title}}{{data.title}},也不transclude {{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>'
Run Code Online (Sandbox Code Playgroud)

现在意味着只有模板{{data.title}}得到更新.再次,为什么不是其他3个绑定?

我希望有一些明显的东西在我面前盯着我,我想念它.如果你让我得到这个,我会给你买啤酒,或给你一些积分,或其他一些这样的东西.非常感谢.

Mar*_*cok 113

你的小提琴创建了三个范围:

  1. 与控制器相关的范围Ctrl,因为ng-controller
  2. 一个指令被转换的范围,因为 transclude: true
  3. 一个指令隔离范围,因为 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.

在fiddle2中,在输入之前我们有与fiddle1相同的图片.

输入后my title:

在此输入图像描述

注意新data.title属性出现的位置 - 在转换范围内.隔离范围仍在寻找data.title控制器范围,但这次不存在,因此其title属性值仍为空.

在小提琴3中,在输入之前我们有与fiddle1相同的图片.

输入后my title:

在此输入图像描述

注意新data.title属性出现的位置 - 在隔离范围上.其他任何范围都不能访问隔离范围,因此字符串my title不会出现在其他任何位置.


Angular v1.2的更新:

随着变化eed299a角现在清除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>'
Run Code Online (Sandbox Code Playgroud)

在下面针对Angular v1.3的更新中,进行了此模板更改.


Angular v1.3 +的更新:

从Angular v1.3开始,transcluded范围现在是指令的隔离范围的子代,而不是控制器范围的子代.所以在fiddle1中,在我们输入任何内容之前:

在此输入图像描述

此更新中的图片是使用Peri $ scope工具绘制的,因此图片有点不同.这@表明我们有一个使用@语法的隔离范围属性,粉红色背景意味着该工具无法找到映射的祖先引用(这是真的,因为我们还没有在文本框中输入任何内容).

输入my title文本框后,我们现在有:

在此输入图像描述

使用@绑定的隔离属性将始终在@符号后面的隔离范围中显示插值字符串结果.Peri $ scope也能够在祖先范围内找到这个确切的字符串值,因此它还显示了对该属性的引用.

在小提琴2中,在打字之前我们有与fiddle1相同的图片.

输入后my title:

在此输入图像描述

注意新data.title属性出现的位置 - 在转换范围内.隔离范围仍在寻找data.title控制器范围,但这次不存在,因此其title属性值仍为空.

在小提琴3中,在输入之前我们有与fiddle1相同的图片.

输入后my title:

在此输入图像描述

注意新data.title属性出现的位置 - 在隔离范围上.即使被转换的范围可以通过$parent关系访问隔离范围,它也不会查找title或者data.title- 它只会查看控制器范围(即,它将遵循原型继承),并且控制器范围不会t定义了这些属性.

  • @mikea,我在几个月前写了一个半生不熟的工具.它开始时干净整洁,但随着我开始尝试添加越来越多的用例和功能,它很快就变成了hackish.一个指令解析了很多Angular对象(一些代码是从Batarang重用的),然后它将有趣的信息发送到Python脚本,该脚本生成一个GraphViz点文件,该文件在服务器端呈现,然后作为图像返回到浏览器. (2认同)

dew*_*ewd 22

在阅读了所有提出的答案之后,包括Mark的精彩原理图,这是我对范围的理解,以及它对我的问题的继承.我希望评论这个图表的位置,以便我可以适当更新.我希望它只是对Mark提出的内容提供了不同的看法:

范围继承


Roy*_*ove 8

好问,顺便问一下!希望我的回答是雄辩的......

答案与变换元素如何获得其范围有关.

总而言之,您有两个范围:

  1. 控制器的范围,有$scope.data.title.(由您的input元素隐式添加)
  2. 指令的范围,有$scope.title.

当您更改控制器时$scope.data.title,指令$scope.title也会更改.

您还有两个HTML部分,即transcluded和模板.发生的事情是,被转换的HTML在控制器的范围内,而模板HTML在指令的范围内.因此,转换的HTML不知道任何内容title,并且模板范围对此一无所知data.title

这实际上就是Transclusion的目的 - 允许指令的子元素保持其父作用域,在这种情况下是控制器的作用域.根据设计,transcluded元素不知道它们在指令中,因此无法访问指令的作用域.

另一方面,指令模板只能访问指令的范围.

我已经改变了你的代码,使名称更清晰(但功能相同)

http://jsfiddle.net/yWWVs/2/