I'm trying to use ng-model "within" a ng-repeat directive that is itself nested in a ng-repeat directive.
The following jsfiddle demonstrates my problem and my two attempts to solve it.
My Controller is defined as follows:
var mod = angular.module('TestApp', []);
mod.controller('TestCtrl', function ($scope) {
var machine = {};
machine.noteMatrix = [
[false, false, false],
[false, true, false],
[false, false, false]
];
$scope.machine = machine;
// ...
});
1.
<table>
<thead>
<tr>
<th>--</th>
<th ng-repeat="no in machine.noteMatrix[0]">{{$index+1}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="track in machine.noteMatrix">
<td>--</td>
<td ng-repeat="step in track">
<input type="checkbox" ng-model="track[$index]"> {{step}}
</td>
</tr>
</tbody>
</table>
The first example/attempt updates the machine.noteMatrix inside the controller, but everytime a checkbox is pressed, angularjs displays the following error twice in the javascript console:
Duplicates in a repeater are not allowed. Repeater: step in track
and sometimes it will also display this error:
Duplicates in a repeater are not allowed. Repeater: no in machine.noteMatrix[0]
2.
<table>
<thead>
<tr>
<th>--</th>
<th ng-repeat="no in machine.noteMatrix[0]">{{$index+1}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="track in machine.noteMatrix">
<td>--</td>
<td ng-repeat="step in track">
<input type="checkbox" ng-model="step"> {{step}}
</td>
</tr>
</tbody>
</table>
The second example/attempt reads the data correctly from the noteMatrix and no errors are displayed in the javascript console when checking/unchecking the checkboxes. However changing their states is not updating the machine.noteMatrix in the controller (press the "Show Matrix" button to see the matrix in the jsfiddle).
Can anyone shed a light on this? :)
This is a common issue for people in Angular. What's happening is ng-repeat creates it's own scope, and if you pass an array of value types into it (such as an array of booleans), updating them will not update the parent scope. You need to pass an array of reference types to the ng-repeat and update those in order for it to persist:
Here is a solution showing this based off of your fiddle
machine.noteMatrix = [
[
{ value: false },
{ value: false },
{ value: false }
],
[
{ value: false },
{ value: true },
{ value: false }
],
[
{ value: false },
{ value: false },
{ value: false }
]
];
It's ugly, I know, but the alternative is uglier. You'd need to do something to manage your own loop and reference the values via the $parent or $parent.$parent object. I don't recommend this.
Your first solution seems to be correct.
This appears to be a bug, introduced in the unstable branch of angularJS (you are using 1.1.4, which is unstable - the stable version, 1.0.6, works as expected)
EDIT:
Turns out this isn't a bug, but a new feature - the ngRepeat directive now allows for a tracking function to be defined (associating the model's id with the DOM element), and no longer allows for these tracking variables to be repeated. See the corresponding commit, the docs for 1.1.4 on ngRepeat and the changelog
You don't need to alter your model or access the $parent. What's missing is "track by $index":
<tr ng-repeat="track in machine.noteMatrix">
<td>--</td>
<td ng-repeat="step in track track by $index">
<input type="checkbox" ng-model="track[$index]"> {{step}}
</td>
</tr>
More information: Angular ng-repeat dupes
I'm not sure if track by existed yet when the question was asked, so the other answers may have been correct at the time, but in current Angular this is the way to go.
来源:https://stackoverflow.com/questions/15973985/using-ng-model-within-nested-ng-repeat-directives