AngularJS中具有ng-repeat范围的指令隔离范围 [英] Directive isolate scope with ng-repeat scope in AngularJS

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

问题描述

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

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.

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

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.

所以我知道我的代码由于ng-repeat指令创建的作用域而失败.我自己的指令创建了一个隔离范围,并与父作用域中的对象进行了双向数据绑定.我的指令将为该绑定变量分配一个新的对象值,当我的指令不带ng-repeat使用(父变量已正确更新)时,这将非常有效.但是,对于ng-repeat,赋值会在ng-repeat范围内创建一个新变量,并且父变量看不到更改.所有这些都是根据我的阅读所预期的.

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.

我还读到,当给定元素上有多个指令时,只会创建一个作用域.并且可以在每个指令中设置priority来定义指令的应用顺序;指令按优先级排序,然后调用其编译功能(在 http://docs.angularjs.org/中搜索优先级一词指南/指令).

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).

所以我希望我可以使用优先级来确保我的指令先运行并最终创建一个隔离范围,并且当ng-repeat运行时,它会重新使用隔离范围而不是创建一个原型上的作用域从父范围继承. ng-repeat文档指出该指令以优先级1000运行.不清楚1是较高优先级还是较低优先级.当我在指令中使用优先级1时,它没有什么不同,因此我尝试了2000.但这使情况变得更糟:我的双向绑定变为undefined,而我的指令不显示任何内容.

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.

我创建了一个小提琴来显示我的问题.我已经在指令中注释了priority设置.我有一个名称对象列表和一个名为name-row的指令,该指令显示名称对象中的名字和姓氏字段.单击显示的名称时,我希望它在主作用域中设置一个selected变量.名称数组selected变量使用双向数据绑定传递给name-row指令.

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.

我知道如何通过调用主作用域中的函数来使其工作.我还知道,如果selected在另一个对象内部,并且绑定到外部对象,则一切正常.但是我目前对那些解决方案不感兴趣.

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.

相反,我的问题是:

  • 如何防止ng-repeat创建从父作用域继承的原型作用域,而是使用我的指令的isolate-scope?
  • 为什么我的指令中的优先级2000无法正常工作?
  • 使用Batarang,是否可以知道正在使用哪种类型的示波器?
  • 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不会影响您选择的隔离范围
  • 传递给ngRepeat的参数用于指令的属性 do 使用原型继承的范围
  • 您的指令不起作用的原因与隔离范围无关
  • 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>

这是 JSFiddle ,表明它无法正常工作.您将获得与指令中完全相同的结果.

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

为什么不起作用?因为AngularJS中的范围使用原型继承.您父级范围内的值selected原始.在JavaScript中,这意味着当子级设置相同的值时,它将被覆盖. AngularJS范围中有一条黄金法则:模型值应始终始终包含..也就是说,它们永远都不应该是原始的.有关更多信息,请参见此SO答案.

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:

请注意,已在ngRepeat范围上创建了新的selected属性.控制器范围003未被更改.

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:

因此,您的问题实际上根本不是由ngRepeat引起的-它是由AngularJS中的一条黄金法则引起的.修复它的方法是简单地使用对象属性:

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>

这是第二个JSFiddle ,它也可以显示此效果.

Here is a second JSFiddle showing this works too.

这里的作用域最初是这样的:

Here is what the scopes look like initially:

点击第一项后:

在这里,控制器作用域会受到影响.

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.

最初的范围:

单击第一项后的范围:

总结:再次,您的问题与隔离范围无关,也与ngRepeat的工作方式无关.您的问题是您违反了导致此问题的已知规则. AngularJS中的模型应始终具有..

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天全站免登陆