1

See the minimal AngularJS app below.

My expectation was that clicking a li would change the name and number in the paragraph, but they don't change away from their original value. Any ideas why?

<div ng-app ng-init="things=[ { name: 'one', num: 1 }, { name: 'two', num: 2 } ]; currentThing = things[0]">
  <p>name: {{currentThing.name}} num: {{currentThing.num}}</p>
  <ul>
    <li ng-click="currentThing=thing" ng-repeat="thing in things">{{thing.name}}</li>
  </ul>
</div>

Editable, runnable JSFiddle: http://jsfiddle.net/JbfZ5/1/

Henrik N
  • 15,786
  • 5
  • 82
  • 131
  • Tried with a controller instead of ng-init; same thing http://jsfiddle.net/JbfZ5/2/ – Henrik N Jun 11 '14 at 16:14
  • But if I do `ng-click=doIt(thing)` and do `$scope.currentThing = thing` in that method in the controller, it does work. Why? http://jsfiddle.net/JbfZ5/3/ – Henrik N Jun 11 '14 at 16:17
  • Changing `currentThing` to `things.currentThing` also works for some reason: http://jsfiddle.net/JbfZ5/5/ – Henrik N Jun 11 '14 at 16:42

1 Answers1

2

This is due to the fact that when using ng-repeat each template instance gets its own scope and due to how prototypal inheritance works in JavaScript.

In short, when you click a li element it will create the currentThing property on the newly created child scope belonging to the template, instead of updating currentThing of the parent.

If you use this instead and click the second li you will notice that it updates its own scope:

<li ng-click="currentThing=thing" ng-repeat="thing in things">
  <pre>{{ currentThing | json }}</pre>
</li>

Demo: http://jsfiddle.net/A3eCe/

The recommended way to get around this is to use an object, for example:

<div ng-app ng-init="viewModel = { things: [ { name: 'one', num: 1 }, { name: 'two', num: 2 } ] }; viewModel.currentThing = viewModel.things[0]">
    <p>name: {{ viewModel.currentThing.name}} num: {{ viewModel.currentThing.num}}</p>
    <ul>
        <li ng-click="viewModel.currentThing = thing" ng-repeat="thing in viewModel.things">{{thing.name}}</li>
    </ul>
</div>

Demo: http://jsfiddle.net/4suvy/

An excellent explanation on the issue can be found here.

Community
  • 1
  • 1
tasseKATT
  • 38,470
  • 8
  • 84
  • 65