在 AngularJS 中使用 ng-repeat 范围指令隔离范围 [英] Directive isolate scope with ng-repeat scope in AngularJS

查看:21
本文介绍了在 AngularJS 中使用 ng-repeat 范围指令隔离范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有隔离范围的指令(以便我可以在其他地方重用该指令),当我将此指令与 ng-repeat 一起使用时,它无法工作.

我已阅读有关此主题的所有文档和 Stack Overflow 答案并了解这些问题.我相信我已经避免了所有常见的问题.

所以我知道我的代码失败是因为 ng-repeat 指令创建的范围.我自己的指令创建了一个隔离范围,并对父范围中的对象进行双向数据绑定.我的指令将为这个绑定变量分配一个新的对象值,当我的指令在没有 ng-repeat 的情况下使用时,这可以完美地工作(父变量已正确更新).但是,对于 ng-repeat,赋值会在 ng-repeat 范围内创建一个新变量,而父变量看不到更改.根据我所阅读的内容,所有这些都符合预期.

我还读到,当给定元素上有多个指令时,只会创建一个作用域.并且可以在每个指令中设置 priority 以定义应用指令的顺序;指令按优先级排序,然后调用它们的编译函数(在 也展示了这个作品.

以下是范围最初的样子:

点击第一项后:

此处,控制器作用域正在按需要受到影响.

此外,为了证明这仍然适用于具有隔离范围的指令(因为,这与您的问题无关),这里是 JSFiddle 也是如此,视图必须反映对象.您会注意到唯一必要的更改是使用 object 而不是 primitive.

最初的范围:

点击第一项后的范围:

总结:再一次,您的问题不在于隔离范围,也不在于 ngRepeat 的工作方式.您的问题是您违反了已知会导致此问题的规则.AngularJS 中的模型应该总是有一个 ..

I have a directive with an isolate-scope (so that I can reuse the directive in other places), and when I use this directive with an ng-repeat, it fails to work.

I have read all the documentation and Stack Overflow answers on this topic and understand the issues. I believe I have avoided all the usual gotchas.

So I understand that my code fails because of the scope created by the ng-repeat directive. My own directive creates an isolate-scope and does a two-way data-binding to an object in the parent scope. My directive will assign a new object-value to this bound variable and this works perfectly when my directive is used without ng-repeat (the parent variable is updated correctly). However, with ng-repeat, the assignment creates a new variable in the ng-repeat scope and the parent variable does not see the change. All this is as expected based on what I have read.

I have also read that when there are multiple directives on a given element, only one scope is created. And that a priority can be set in each directive to define the order in which the directives are applied; the directives are sorted by priority and then their compile functions are called (search for the word priority at http://docs.angularjs.org/guide/directive).

So I was hoping I could use priority to make sure that my directive runs first and ends up creating an isolate-scope, and when ng-repeat runs, it re-uses the isolate-scope instead of creating a scope that prototypically inherits from the parent scope. The ng-repeat documentation states that that directive runs at priority level 1000. It is not clear whether 1 is a higher priority level or a lower priority level. When I used priority level 1 in my directive, it did not make a difference, so I tried 2000. But that makes things worse: my two-way bindings become undefined and my directive does not display anything.

I have created a fiddle to show my issue. I have commented out the priority setting in my directive. I have a list of name objects and a directive called name-row that shows the first and last name fields in the name object. When a displayed name is clicked, I want it to set a selected variable in the main scope. The array of names, the selected variable are passed to the name-row directive using two-way data-binding.

I know how to get this to work by calling functions in the main scope. I also know that if selected is inside another object, and I bind to the outer object, things would work. But I am not interested in those solutions at the moment.

Instead, the questions I have are:

  • How do I prevent ng-repeat from creating a scope that prototypically inherits from the parent scope, and instead have it use my directive's isolate-scope?
  • Why is priority level 2000 in my directive not working?
  • Using Batarang, is it possible to know what type of scope is in use?

解决方案

Okay, through a lot of the comments above, I have discovered the confusion. First, a couple of points of clarification:

  • ngRepeat does not affect your chosen isolate scope
  • the parameters passed into ngRepeat for use on your directive's attributes do use a prototypically-inherited scope
  • the reason your directive doesn't work has nothing to do with the isolate scope

Here's an example of the same code but with the directive removed:

<li ng-repeat="name in names"
    ng-class="{ active: $index == selected }"
    ng-click="selected = $index">
    {{$index}}: {{name.first}} {{name.last}}
</li>

Here is a JSFiddle demonstrating that it won't work. You get the exact same results as in your directive.

Why doesn't it work? Because scopes in AngularJS use prototypical inheritance. The value selected on your parent scope is a primitive. In JavaScript, this means that it will be overwritten when a child sets the same value. There is a golden rule in AngularJS scopes: model values should always have a . in them. That is, they should never be primitives. See this SO answer for more information.


Here is a picture of what the scopes initially look like.

After clicking the first item, the scopes now look like this:

Notice that a new selected property was created on the ngRepeat scope. The controller scope 003 was not altered.

You can probably guess what happens when we click on the second item:


So your issue is actually not caused by ngRepeat at all - it's caused by breaking a golden rule in AngularJS. The way to fix it is to simply use an object property:

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

Here is a second JSFiddle showing this works too.

Here is what the scopes look like initially:

After clicking the first item:

Here, the controller scope is being affected, as desired.

Also, to prove that this will still work with your directive with an isolate scope (because, again, this has nothing to do with your problem), here is a JSFiddle for that too, the view must reflect the object. You'll note that the only necessary change was to use an object instead of a primitive.

Scopes initially:

Scopes after clicking on the first item:

To conclude: once again, your issue isn't with the isolate scope and it isn't with how ngRepeat works. Your problem is that you're breaking a rule that is known to lead to this very problem. Models in AngularJS should always have a ..

这篇关于在 AngularJS 中使用 ng-repeat 范围指令隔离范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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