对 Angularjs 内嵌和隔离作用域感到困惑绑定 [英] Confused about Angularjs transcluded and isolate scopes & bindings

查看:21
本文介绍了对 Angularjs 内嵌和隔离作用域感到困惑绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力理解模型的范围及其与范围有限的指令相关的绑定.

我知道限制指令的范围意味着 controller.$scope 和directive.scope 不再是一回事.但是,我对在指令模板或 html 中放置模型如何影响数据绑定感到困惑.我觉得我错过了一些非常基本的东西,为了继续前进,我需要理解这一点.

获取以下代码(在这里小提琴: Angular 现在会在转置前清除转置点,因此Template title: ...Template data.title: ... 部分不会显示,除非你修改模板使得 ng-transclude 本身,例如:

'<h3>模板标题:<span style="color:red">{{title}}</span></h3>'+'<h3>模板数据.title:<span style="color:red">{{data.title}}</span></h3>'+'<div ng-transclude></div>'

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

<小时>

Angular v1.3+ 的更新:

从 Angular v1.3 开始,嵌入的作用域现在是指令的隔离作用域的子级,而不是控制器作用域的子级.所以在 fiddle1 中,在我们输入任何东西之前:

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

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

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

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

输入我的标题后:

注意新的 data.title 属性出现的位置——在嵌入的作用域上.隔离作用域仍在控制器作用域上寻找 data.title ,但这次它不在那里,所以它的 title 属性值保持为空.

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

输入我的标题后:

注意新的 data.title 属性出现的位置——在隔离作用域上.即使被嵌入的作用域可以通过 $parent 关系访问隔离作用域,它也不会在那里寻找 titledata.title-- 它只会在控制器范围内查找(即,它将遵循原型继承),并且控制器范围没有定义这些属性.

I am struggling to understand the scope of models and their bindings in respect of directives which have limited scope.

I get that restricting the scope on a directive means that controller.$scope and directive.scope are no longer the same thing. However, I am confused about how the placing of models either within the directive template or in the html affects data binding. I feel I'm missing something very fundamental and to move on I need to understand this.

Take the following code (fiddle here: 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>

The model only updates {{title}} within the template, and {{data.title}} in the transclusion. Why not {{title}} in the transclusion nor {{data.title}} in the template?

Moving the input to within the transclusion like so (fiddle here: 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>

now means only transclude {{data:title}} gets updated. Why not either template {{title}} or {{data.title}}, nor transclude {{title}}?

And finally, moving the input to within the template, like so (fiddle here: 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>'

Now means that only template {{data.title}} gets updated. Again, why not the other 3 bindings?

I hope there is something obvious staring me in the face and I'm missing it. If you get me to get this, I'll buy you a beer, or give you some points, or some other such thing. Many thanks.

解决方案

Your fiddles create three scopes:

  1. a scope associated with controller Ctrl, because of ng-controller
  2. a directive transcluded scope, because of transclude: true
  3. a directive isolate scope, because of scope: { ... }

In fiddle1, before we type anything into the text box we have the following:

Scope 003 is the scope associated with the controller. Since we didn't type into the textbox yet, there is no data property. In isolate scope 004, we see that a title property was created, but it is empty. It is empty because the parent scope doesn't have a data.title property yet.

After typing my title into the textbox, we now have:

Controller scope 003 now has a new data object property (which is why it is colored yellow), which has a title property now set to my title. Since isolate scope property title is one-way databound to the interpolated value of data.title, it also gets the value my title (the value is colored yellow because it changed).

The transcluded scope prototypically inherits from the controller scope, so inside the transcluded HTML, angular can follow the prototype chain and find $scope.data.title in the parent scope (but $scope.title doesn't exist there).

The isolate scope only has access to its own properties, hence only property title.

In fiddle2, before typing we have the same picture as in fiddle1.

After typing my title:

Notice where the new data.title property showed up -- on the transcluded scope. The isolate scope is still looking for data.title on the controller scope, but its not there this time, so its title property value remains empty.

In fiddle3, before typing we have the same picture as in fiddle1.

After typing my title:

Notice where the new data.title property showed up -- on the isolate scope. None of the other scopes have access to the isolate scope, so the string my title won't appear anywhere else.


Update for Angular v1.2:

With change eed299a Angular now clears the transclusion point before transcluding, so the Template title: ... and Template data.title: ... parts won't show up unless you modify the template such that ng-transclude is by itself, such as:

'<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>'

In the update below for Angular v1.3, this template change was made.


Update for Angular v1.3+:

Since Angular v1.3, the transcluded scope is now a child of the directive's isolate scope, rather than a child of the controller scope. So in fiddle1, before we type anything:

The pictures in this update are drawn with the Peri$scope tool, so the pictures are a bit different. The @ indicates we have an isolate scope property that uses the @ syntax, and the pink background means that the tool was unable to find an ancestor reference for the mapping (which is true, since we didn't type anything in to the textbox yet).

After typing my title into the textbox, we now have:

Isolate properties that use @ binding will always show the interpolated string result in the isolate scope after the @ symbol. Peri$scope was also able to find this exact string value in an ancestor scope, so it also shows a reference to that property.

In fiddle 2, before typing we have the same picture as in fiddle1.

After typing my title:

Notice where the new data.title property showed up -- on the transcluded scope. The isolate scope is still looking for data.title on the controller scope, but its not there this time, so its title property value remains empty.

In fiddle3, before typing we have the same picture as in fiddle1.

After typing my title:

Notice where the new data.title property showed up -- on the isolate scope. Even though the transcluded scope has access to the isolate scope via the $parent relationship, it won't look there for title or data.title -- it will only look in the controller scope (i.e., it will follow the prototypal inheritance), and the controller scope doesn't have these properties defined.

这篇关于对 Angularjs 内嵌和隔离作用域感到困惑绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆