指令在AngularJS中用ng-repeat范围隔离范围
我有一个隔离范围指令(这样我可以在其他地方重复使用指令),当我用ng-repeat
使用这个指令时,它无法工作。
我已经阅读了关于这个主题的所有文档和堆栈溢出的答案,并理解了这些问题。 我相信我已经避免了所有常见的问题。
所以我明白我的代码失败,因为由ng-repeat
指令创build的范围。 我自己的指令创build一个隔离作用域,并对父作用域中的对象执行双向数据绑定。 我的指令将为这个绑定variables赋值一个新的对象值,当我的指令没有使用ng-repeat
(父variables被正确更新)时,这个工作就完美了。 但是,在ng-repeat
,赋值在ng-repeat
范围内创build一个新variables,而父variables不会看到变化。 所有这一切,正如我所读的一样。
我也读过,当给定元素有多个指令时,只有一个作用域被创build。 并且可以在每个指令中设置priority
来定义指令的应用顺序; 指令按优先级sorting,然后调用其编译函数(在http://docs.angularjs.org/guide/directive上search优先级字)。
所以我希望能够使用优先级来确保我的指令首先运行,最终创build一个隔离范围,而当ng-repeat
运行时,它将重新使用隔离范围,而不是创build一个从原型inheritance的范围父范围。 ng-repeat
文档指出该指令以优先级1000
运行。 不清楚1
是较高的优先级还是较低的优先级。 当我在我的指令中使用优先级1
时,没有什么区别,所以我尝试了2000
。 但是,这使事情变得更糟:我的双向绑定变得undefined
,我的指令不显示任何东西。
我创造了一个小提琴来展示我的问题 。 我已经指出了我的指令中的priority
设置。 我有一个名称对象的列表和一个名为name-row
的指令,显示名称对象中的名字和姓氏字段。 当显示的名称被点击时,我想让它在主要范围内设置一个selected
variables。 名称数组, selected
variables使用双向数据绑定传递给name-row
指令。
我知道如何通过调用主范围中的函数来实现这个function。 我也知道,如果selected
是在另一个对象内,而我绑定到外部对象,事情会起作用。 但我目前对这些解决scheme不感兴趣。
相反,我所拥有的问题是:
- 如何防止
ng-repeat
创build从父范围原型inheritance的范围,而是使用我的指令的隔离范围? - 为什么我的指令中的优先级为
2000
? - 使用Batarang,是否有可能知道正在使用什么types的范围?
好吧,通过上面的很多评论,我发现了这个混乱。 首先,澄清几点:
- ngRepeat不会影响您select的隔离范围
- 传递给ngRepeat以用于指令属性的参数确实使用了原型inheritance的作用域
- 您的指令不起作用的原因与隔离范围无关
这是一个相同的代码,但删除了指令的例子:
<li ng-repeat="name in names" ng-class="{ active: $index == selected }" ng-click="selected = $index"> {{$index}}: {{name.first}} {{name.last}} </li>
这是一个JSFiddle,certificate它不起作用。 你得到了和你的指令完全一样的结果。
为什么不起作用? 因为AngularJS中的范围使用原型inheritance。 在父范围上selected
的值是一个基元 。 在JavaScript中,这意味着当孩子设置相同的值时,它将被覆盖。 在AngularJS范围内有一个黄金法则:模型值应该总是有一个.
在他们中。 也就是说,他们不应该是原始的。 看到这个答案的更多信息。
这是一个范围最初看起来像什么的图片。
点击第一个项目后,范围如下所示:
请注意,在ngRepeat作用域上创build了一个新的selected
属性。 控制器范围003未被更改。
您大概可以猜到当我们点击第二项时会发生什么:
所以你的问题实际上不是由ngRepeat造成的 – 这是由AngularJS打破了金科玉律的缘故。 解决这个问题的方法是简单地使用一个对象属性:
$scope.state = { selected: undefined };
<li ng-repeat="name in names" ng-class="{ active: $index == state.selected }" ng-click="state.selected = $index"> {{$index}}: {{name.first}} {{name.last}} </li>
这里还有第二个JSFiddle展示了这个工作。
以下是最初的范围:
点击第一项后:
在这里,控制器范围正在受到影响,如果需要的话。
另外,为了certificate这个指令仍然适用于隔离范围(因为这与你的问题无关),这里也是一个JSFiddle ,这个视图必须反映这个对象。 你会注意到唯一必要的改变是使用一个对象而不是原始的 。
最初范围:
点击第一项后的范围:
总而言之,你的问题不是孤立的范围,而是与ngRepeat的工作方式不同。 你的问题是你违反了一个已知导致这个问题的规则。 AngularJS中的模型应该总是有一个.
。
不要直接试图避免回答你的问题,而是看看下面的小提琴:
关键在于,不要试图与Angular的传统行为作斗争和改变,你可以把你的指令构造成与ng-repeat
一起工作,而不是试图重写它。
在您的模板中:
<name-row in-names-list="names" io-selected="selected"> </name-row>
在你的指令中:
template: ' <ul>' + ' <li ng-repeat="name in inNamesList" ng-class="activeClass($index)" >' + ' <a ng-click="setSelected($index)">' + ' {{$index}} - {{name.first}} {{name.last}}' + ' </a>' + ' </li>' + ' </ul>'
回答你的问题:
-
ng-repeat
将创build一个范围,你真的不应该试图改变这一点。 - 指令中的优先级不仅仅是执行顺序 – 请参阅: AngularJS:HTML编译器如何安排编译顺序?
- 在Batarang中,如果检查性能选项卡,则可以看到每个范围的expression式,并检查它是否符合您的期望。