我有一个带隔离范围的指令(这样我可以在其他地方重用该指令),当我将这个指令与ng-repeat
一起使用时,它无法工作。
我已阅读有关此主题的所有文档和Stack Overflow答案,并了解问题。我相信我已经避免了所有常见的陷阱。
所以我理解我的代码因ng-repeat
指令创建的范围而失败。我自己的指令创建了一个isolate-scope,并对父作用域中的对象进行双向数据绑定。我的指令将为此绑定变量分配一个新的对象值,当我的指令在没有ng-repeat
的情况下使用时(父变量被正确更新),这种方法非常有效。但是,对于ng-repeat
,赋值会在ng-repeat
范围内创建一个新变量,而父变量则看不到更改。所有这些都是基于我所读到的预期。
我还读过,当给定元素上有多个指令时,只创建一个范围。并且可以在每个指令中设置priority
以定义指令的应用顺序;指令按优先级排序,然后调用它们的编译函数(在http://docs.angularjs.org/guide/directive搜索单词优先级。)。
所以我希望我可以使用优先级来确保我的指令先运行并最终创建一个隔离范围,当ng-repeat
运行时,它会重新使用隔离范围而不是创建一个范围原型继承自父范围。 ng-repeat
文档声明该指令以优先级1000
运行。目前尚不清楚1
是优先级更高还是优先级更低。当我在我的指令中使用优先级1
时,它没有什么区别,所以我尝试了2000
。但这会让事情变得更糟:我的双向绑定变为undefined
,我的指令不会显示任何内容。
我创建了a fiddle to show my issue。我在我的指令中注释了priority
设置。我有一个名称对象列表和一个名为name-row
的指令,它显示了名称对象中的名字和姓氏字段。单击显示的名称时,我希望它在主范围中设置selected
变量。使用双向数据绑定将名称数组selected
变量传递给name-row
指令。
我知道如何通过调用主范围中的函数来使其工作。我也知道,如果selected
在另一个对象中,并且我绑定到外部对象,事情就会起作用。但我现在对这些解决方案不感兴趣。
相反,我的问题是:
ng-repeat
创建原型继承自父作用域的作用域,而是让它使用我的指令的isolate-scope?2000
不起作用?答案 0 :(得分:203)
好的,通过上面的很多评论,我发现了混乱。首先,澄清几点:
以下是相同代码的示例,但删除了指令:
<li ng-repeat="name in names"
ng-class="{ active: $index == selected }"
ng-click="selected = $index">
{{$index}}: {{name.first}} {{name.last}}
</li>
这是一个JSFiddle,证明它不起作用。您将得到与指令完全相同的结果。
为什么不起作用?因为AngularJS中的范围使用原型继承。父作用域上的值selected
是原语。在JavaScript中,这意味着当子设置相同的值时它将被覆盖。 AngularJS范围中有一条黄金法则:模型值始终中包含.
。也就是说,它们永远不应该是原始的。有关详细信息,请参阅this SO answer。
以下是范围最初的样子。
点击第一项后,范围现在如下所示:
请注意,在ngRepeat范围内创建了新的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>
这是second JSFiddle,显示这也有效。
这是范围最初的样子:
点击第一项后:
此处,控制器范围正在受到影响。
另外,为了证明这仍然适用于具有隔离范围的指令(因为,这与您的问题无关),这里也是JSFiddle,视图必须反映物体。您会注意到唯一必要的更改是使用对象而不是原语。
最初的范围:
点击第一项后的范围:
总结:再一次,您的问题不在于隔离范围,而在于ngRepeat的工作原理。你的问题是,你正在打破一个已知导致这个问题的规则。 AngularJS中的模型应始终具有.
。
答案 1 :(得分:6)
不要直接试图避免回答你的问题,而是看看下面的小提琴:
关键是,不是试图打击和改变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
会创建一个范围,你真的不应该试图改变它。