Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ng-animate animate wrong item when using 'track by $index' in ng-repeat

I am trying to create the application that user can choose different types of block and stack them together to create unique template.

Since I want the user be able to add same block into the template multiple times, I have to use 'track by $index' to accomplish this:

<li ng-repeat="chosen in chosenlist track by $index">

However, when I tried to add animation with ng-animate, the animation for removing block is animate on last block in the template instead of the removing block. I put the code in jsfiddle here http://jsfiddle.net/FC9c7/6/.

Try adding new block by choosing layout 1, 2, or 3. And when you click 'remove block' you will see the problem.

like image 366
designil Avatar asked Aug 25 '13 19:08

designil


2 Answers

You could make a copy of the object before adding it to the chosen list. This way you could track by $id(chosen),which is the default. You are adding the same object to the chosen list so angular will see duplicates in the repeater for ng-repeat.

change the add_layout function the following and remove the track by expression in the ng-repeat. This is just another solution. You might have large objects where performing a deep copy may not make sense.

$scope.add_layout = function(new_layout) {
    $scope.chosenlist.push(angular.copy(new_layout));

};

like image 22
Philip Leicht Avatar answered Sep 18 '22 12:09

Philip Leicht


Here's what I believe it's happening: since you're tracking the items by their indices, every time you remove one from the list, what changes is the index of the last element, making Angular believe that it was the one removed. That becomes sort of obvious when you print the index next to its element. Take a look at this modified jsFiddle.

One solution would be to create new elements with unique ids and then track by those ids:

Javascript

$scope.add_layout = function(new_layout) {
  new_layout = angular.copy(new_layout);
  new_layout.id = new Date().getUTCMilliseconds();
  $scope.chosenlist.push(new_layout);
};

HTML

<li ng-repeat="chosen in chosenlist track by chosen.id" ng-animate="'animate'">

jsFiddle here.

But since it creates new elements, you won't be able to keep them in sync with the original object, and I don't know whether that's acceptable to you.

I'll try to check out if the new animation system in Angular 1.2 RC1 solves this particular problem and if I find out something I'll update this answer. But I'm not confident it does, though. :(

like image 125
Michael Benford Avatar answered Sep 20 '22 12:09

Michael Benford