Domanda

I am getting, what I believe to be, an odd behaviour when adding arrays to an object in an ng-repeat.

Due to the "Duplicates in a repeater are not allowed" error I am using track by $index but when I try to show / hide a row everything that was added is toggled. I have tried passing the index into an ng-click and even setting the value directly in the ng-click

Here is some sample code and a jsFiddle demonstration

HTML excerpt:

<tbody ng-repeat="person in object track by $index" ng-show="person.visible">
<tr>
    <td>{{ person.name }}</td>
    <td>{{ person.age }}</td>
    <td>
        <a href ng-click="togglePerson($index)">Hide</a>
    </td>
    <!-- <td>
        <a href ng-click="person.visible = !person.visible">Hide</a>
    </td> -->
</tr>
</tbody>

Javascript:

myApp.controller('myController', function ($scope) {
    $scope.init = function () {
        $scope.object = [{
            name: "Billy",
            age: 21,
            visible: true
        }];
        $scope.newEntry = {
            name: 'Ralph',
            age: 16,
            visible: true
        };
    };

    $scope.addPerson = function () {
        $scope.object.push($scope.newEntry);
    };

    $scope.togglePerson = function (index) {
        console.log(index); // Index is being passed properly
        $scope.object[index].visible = !$scope.object[index].visible;
    };
});

I have done quite a few visibility toggles in the past within a repeater (never with a track by $index) but I can't seem to determine where I went wrong. Is this even related to the tracking / array comparison?


Edit

To be clear, my demonstration is not how I am using this code. I am actually toggling a second rows visibility. I know that my demonstration is flawed since once you toggle hidden you can't toggle back.

È stato utile?

Soluzione

When you push an object into an array it pushes the object by reference. Each time you call this

$scope.addPerson = function () {
        $scope.object.push($scope.newEntry);
    };

You are basically pushing the same object at different index positions of the array. Now this same object is repeated over in the repeater.

And when you toggle :

$scope.togglePerson = function (index) {
        console.log(index); // Index is being passed properly
        $scope.object[index].visible = !$scope.object[index].visible;
    };

you are basically setting the same objects property on all the array indexes, since the array has the same object at all the indexes.

You need to do a copy of the object before pushing it into the array so that you get a new object every single time.

$scope.addPerson = function () {
        $scope.object.push(angular.copy($scope.newEntry));
    };

Here is a fiddle that demonstrates this :

jsFiddle demonstration

NOTE : This has nothing to do with array track by $index

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top