Search code examples
javascriptcssangularjssignalrng-animate

Using ngAnimate with ngRepeat with spliced elements


I am working on a proof of concept SPA web app using Angular and SignalR. I want my client app to animate the new items that are inserted into a list using ngAnimate that are generated using ngRepeat.

Before I inserted new items this way:

signalRhub.client.broadcastData = function (data) {
                    $scope.customers.push(data);
                    $scope.$apply(); 
                };

But now I wanted to insert the new items at the top of the list instead of at the bottom, and remove the last item of the list if the list exceeds five items:

signalRhub.client.broadcastData = function (data) {
                    $scope.customers.splice(0, 0, data);
                    if ($scope.customers.length > 5) { $scope.customers.splice(5, 1); }
                    $scope.$apply(); 
                };

The view:

<tr class="customerList" ng-repeat="customer in customers track by $index">
    <td style="font-size:x-large; width:50%">
        {{customers.customerId}}
    </td>
    <td style="font-size:x-large; width:50%">
        {{customers.appointments[0].appointmentId}}
    </td>
</tr>

CSS:

.customerList.ng-enter {
    transition:1s linear all;
    opacity:0;
}
.customerList.ng-enter-active {
    opacity: 1;
}

.customerList.ng-leave-active {
    opacity:0;
}

The problem with this is that ngAnimate is animating the last line until it is spliced out of the list because the list is too long. How do I animate only the new items that are spliced-in the beginning of the list?


Solution

  • I have found a way around this problem so I will post it here in case somebody else encounters the same problem.

    What I did is simply to create a custom Angular filter, called 'reverse', for enumerating a list using ngRepeat with new entries adding in on top of the list:

    controller:

    signalRhub.client.broadcastData = function (data) {
                        $scope.customers.push(data);
                        $scope.$apply(); 
                    };
    

    filter:

    function (eventsApp) {
            'use strict';
            app.filter('reverse', function () {
                return function (items) {
                    return items.slice().reverse();
                };
            });
        });
    

    html:

    <tr class="customerList" ng-repeat="customer in customers | reverse">
        <td style="font-size:x-large; width:50%">
            {{customers.customerId}}
        </td>
        <td style="font-size:x-large; width:50%">
            {{customers.appointments[0].appointmentId}}
        </td>
    </tr>
    

    This way it is possible to benefit from the CSS classes generated by ngAnimate.