指令在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的指令,显示名称对象中的名字和姓氏字段。 当显示的名称被点击时,我想让它在主要范围内设置一个selectedvariables。 名称数组, selectedvariables使用双向数据绑定传递给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中的模型应该总是有一个.

不要直接试图避免回答你的问题,而是看看下面的小提琴:

http://jsfiddle.net/dVPLM/

关键在于,不要试图与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式,并检查它是否符合您的期望。