Bardyl
Bardyl

Reputation: 231

track by in ng-repeat isn't tracking

I'm trying to build a single list which will be updated by clicking through a up and down button. Also, i'm doing this with AngularJS.

Here is my HTML:

<div ng-repeat="element in playlistElements | orderBy: element.position track by element.position"
     class="track {{ element.type }} track-{{ element.position }}">
    <div class="full-line bold">{{ element.firstLine }}</div>
    <div class="full-line">{{ element.lastLine }}</div>
    <div class="track-controls">
        <p>
            <i class="fa fa-arrow-up" ng-if="!$first" ng-click="rebuildPlaylist(element, 'up')"></i>
            <i class="fa fa-arrow-down" ng-if="!$last" ng-click="rebuildPlaylist(element, 'down')"></i>
            <i class="fa fa-times" ng-click="rebuildPlaylist(element, 'remove')"></i>
        </p>
    </div>
</div>

and here is my controller:

$scope.rebuildPlaylist = function(track, action) {
    var media = {
        id: track.id,
        position: track.position
    };
    console.log(track.position);
    if (action == 'up') {
        $scope.playlistElements[media.position].position = media.position - 1;
        $scope.playlistElements[media.position - 1].position = media.position;
    }
    console.log($scope.playlistElements);
};

When I click on the up arrow "picture", the position value of my playlistElements is updating itself with the good value and my element object seems to be clean in the DOM.

But it seems that is not "reloading" the DOM with the new value of position.

Not sure if i'm clear, so ask me for precisions. I've not using Angular since a really long time so, maybe i'm doing things wrongly.

Thanks for your help :).

Upvotes: 0

Views: 71

Answers (1)

Zonedark
Zonedark

Reputation: 249

I managed to make a working fiddle out of your code samples. You can check it here : JSFIDDLE

<i class="fa fa-arrow-up" ng-if="!$first" ng-click="rebuildPlaylist($index, 'up')"></i>
    <i class="fa fa-arrow-down" ng-if="!$last" ng-click="rebuildPlaylist($index, 'down')"></i>

And :

$scope.rebuildPlaylist = function(index, action) {
if (action == 'up' && index > 0) {
  var tempoStorage = $scope.playlistElements[index];
  $scope.playlistElements[index] = $scope.playlistElements[index - 1];
  $scope.playlistElements[index - 1] = tempoStorage;
}
if (action == 'down' &&  index < $scope.playlistElements.length) {
  var tempoStorage = $scope.playlistElements[index];
  $scope.playlistElements[index] = $scope.playlistElements[index + 1];
  $scope.playlistElements[index + 1] = tempoStorage;
}

Basically two things :

1) "track by" in angular doesn't influence the order of the elements inside the ng-repeat. What track by does it give the ng-repeat something to take into account to keep track of each element. For example, if you have in your repeat element the same element multiple times, angular will lose itself and not be able to display it. Adding "track by" allows you to have a proper display, even with duplicates.

2) What I did was basically give $index to your method call on click, and swap the two elements in your array.Since ng-repeat is based on your array, reversing the order inside it will make the display swap too. Oh and by the way, $index inside ng-repeat represents the index of the current element.

Happy coding!

Upvotes: 2

Related Questions