Directive isolate scope with ng-repeat scope in AngularJS

大城市里の小女人 提交于 2019-11-26 19:14:41
Josh David Miller

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

Alex Osborn

Without directly trying to avoid answering your questions, instead take a look at the following fiddle:

http://jsfiddle.net/dVPLM/

Key point is that instead of trying to fight and change the conventional behaviour of Angular, you could structure your directive to work with ng-repeat as opposed to trying to override it.

In your template:

    <name-row 
        in-names-list="names"
        io-selected="selected">
    </name-row>

In your directive:

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

In response to your questions:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!