理解Angular中的$scope


Angular scope 使用的一些问题总结

在AngularJS中,child scope一般通过原型式继承自它的parent scope。(directive的scope属性为{...}的情况除外,因为它会创建独立的scope)。在指令中,默认使用的是parent scope,这意味着在指令中改变的任何属性都会反映到其parent scope中。设置scope:true 会在该指令中使用原型继承。

scope的继承通常是直截了当的,但是当你尝试在child scope中使用定义在parent scope的双向数据绑定的时候,它可能就不像你期望的那样起作用了。原因是child scope会重写parent scope中的重名属性,这是原型式继承的一个特征。

注意:ng-repeat, ng-switch, ng-view, ng-include 都会创建新的child scope,上述问题通常出现在这些指令的使用过程中。具体可以看看这个例子

要避免上面的问题有以下几个方法:

  • 总是在ng-model中使用 '.' 即ng-model使用一个对象而不是一个基本类型的值
    这样:<input type="text" ng-model="someObj.prop1">
    而不是:<input type="text" ng-model="prop1">
  • 如果你实在要使用基本类型,可以参照下面两个方法
    1.在child scope中使用$parent.parentScopeProperty,它会阻止child scope创建自己的属性覆盖parent scope上的同名属性
    2.在parent scope中定义一个方法,然后在child scope中调用,将基本类型值通过参数传递给parent

Angular scope 的继承

  • 以下会创建新的scope,并且原型式继承自parent scope:
    ng-repeat, ng-include, ng-switch, ng-view, ng-controller, 设置了scope: true的指令, 设置了transclude: true的指令
  • 以下会创建新的scope,但是不通过原型式继承自parent scope
    设置了 scope: {....}. 这样会创建一个独立的scope

注意,默认情况下,自定义指令并不会创建新的scope,scope:false是默认值

ng-include

假设在controller.js中有以下代码

// 定义一个基本类型的值
$scope.myPrimitive = 50;
// 定义一个对象
$scope.myObject    = {aNumber: 11};

html代码

<script type="text/ng-template" id="/tpl1.html">
    <input ng-model="myPrimitive">
</script>
<div ng-include src="'/tpl1.html'"></div>

<script type="text/ng-template" id="/tpl2.html">
    <input ng-model="myObject.aNumber">
</script>
<div ng-include src="'/tpl2.html'"></div>

上面每个ng-include都会产生一个新的child scope, 原型继承自parent scope

看看结果如下:

第一个input的ng-model是一个基本类型,它不能与parent scope中的表达式实现双向数据绑定,原因在于child scope通过原型继承属性自其parent scope,对于基本类型的值,child scope重写parent scope中的重名属性。

第二个input的ng-model是一个对象,它可以实现双向数据绑定,当ngModel查找一个对象时,它会一直查找到parent scope.

我们也可以对第一个input进行改写如下:

<input ng-model="$parent.myPrimitive">

这里$parent是child scope下的一个属性,该属性指向parent scope

或者在parent scope中定义一个方法来改变基本类型的值,在child scope调用该方法,看代码

// controller.js
$scope.setMyPrimitive = function (value){
    $scope.myPrimitive = value;
}
<input ng-model="myPrimitive" class="form-control" ng-change="setMyPrimitive(myPrimitive)">

效果如下:可以看到可以正常地进行双向数据绑定了

ng-repeat

假设有如下代码:controller.js

$scope.myArrayOfPrimitives = [ 11, 22 ];
$scope.myArrayOfObjects    = [{num: 101}, {num: 202}]

html代码如下:

<ul><li ng-repeat="num in myArrayOfPrimitives">
       <input ng-model="num"></input>
    </li>
</ul>
<ul><li ng-repeat="obj in myArrayOfObjects">
       <input ng-model="obj.num"></input>
    </li>
</ul>

对每一个li,ng-repeat都创建一个新的scope,继承自parent scope,但是同时会将遍历的变量(第一个ul中为num) 作为新的child scope的一个属性,myArrayOfPrimitives[num]的值作为该属性的属性值。

angular中ng-repeat的源码如下:

childScope = scope.$new(); // child scope prototypically inherits from parent scope ...     
childScope[valueIdent] = value; // creates a new childScope property

如果在遍历数组中的每个item是一个基本类型(myArrayOfPrimitives),该item的值会被分配给新child scope的属性,改变这个属性的值(例如使用ng-model),不会改变parent scope中的数组。在第一个ul中,每个child scope有一个num属性独立于数组myArrayOfPrimitives。

如果我们希望改变在item中改变parent scope中的数组,我们需要将model变为一个数组对象

所以,如果数组中的每个item都是一个对象,该对象的一个引用会被分配给child scope的属性,改变child scope的属性值也会改变parent scope中的数组的引用。

今天先搞到这里,原文地址Understanding Scopes

优质内容筛选与推荐>>
1、博主写的Route安排的pkb源代码,注意关键部位的日期排序算法。
2、清除数据库的日志
3、web.xml 中的listener、 filter、servlet 加载顺序及其详解
4、树链剖分
5、SpringMVC探究-----常用获取传递参数的方法


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn