2

I am working with angularjs and ngAnimate but running into issues with how the animations are handled. I have an ng-repeat that displays a series of floated blocks that allow the user to click on the links within them and navigate to a lower level of the page (load new levels data). When one of these links if clicked, I update the $scope.items array with the new level's blocks and this is where the animation behaves awkwardly. The existing blocks slide down while they are fading out to make room for the new blocks that are fading in. I want to fade out the existing blocks and then fade in the new blocks (not simultaneously). I have tried every conceivable thing I can imagine to delay the 'enter' animations to give the 'leave' animations time to finish but have come up empty thus far.

I have distilled my application down to this simple example – the navigate() function in the ng-click usually makes $http requests for new data but I just set it up to return modified data (the animation behavior exactly matches what occurs in my application without the overhead of sharing my full applications with $http requests and data handling).

I appreciate any help. Thanks.

Javascript:

myApp.controller('MyCtrl', ['$scope', function ($scope) {
    $scope.items = [1, 2, 3, 4];
    $scope.navigate = function () {

        var newItems = [];

        for (i = 0; i < $scope.items.length; i++) {
            newItems.push($scope.items[i] + 4);
        }

        $scope.items = newItems;

    };
}]);

HTML:

<div class="block" ng-repeat="item in items">
    <a href="" ng-click="navigate();">
        {{item}}
    </a>
</div>

CSS:

.block {
    background: #e6e6e6;
    width: 100px;
    height: 100px;
    padding: 10px;
    margin: 10px;
    float: left;
    opacity: 1;
}

/* animation css */
.block.ng-enter {
    -webkit-transition: 1s;
    transition: 1s;
    opacity: 0;
}
.block.ng-enter.ng-enter-active {
    opacity: 1;
}
.block.ng-leave {
    -webkit-transition: .9s;
    transition: .9s;
    opacity: 1;
}
.block.ng-leave.ng-leave-active {
    opacity: 0;
}



Demo of the issue: jsfiddle

JRulle
  • 7,448
  • 6
  • 39
  • 61
  • Angular handles animation by delegating to css, this means once angular sets/removes a class on an appearing/disapearing element, imo it has no clue about the time the animation will take, because it is now in the css world. What you want to achieve requires an animation-end callback that can be set using jquery/jqlite animation capabilities, maybe inside a well crafted directive ? – Sbu Feb 12 '15 at 15:03
  • That is where I am struggling... it seems 'hacky' to have some of the animation timing handled in javascript and some of it in CSS. (i.e. the hacky answer I posted below). – JRulle Feb 12 '15 at 15:27
  • There actually is a callback on css animation's end, check this http://stackoverflow.com/questions/6186454/is-there-a-callback-on-completion-of-a-css3-animation – Sbu Feb 13 '15 at 08:44

1 Answers1

1

Hacky answer:

I am able to delay the new items using the $timeout module. Basically, I clear out $scope.items, wait 1 second and then fill it with the new data. I'm really hope there is a better way to do this, but I thought I would share this as it is the only resolution I have found thus far.

myApp.controller('MyCtrl', ['$scope', '$timeout', function ($scope, $timeout) {
    $scope.items = [0, 1, 2, 3, 4];
    $scope.navigate = function () {

        var newItems = [];

        for (i = 0; i < $scope.items.length; i++) {
            newItems.push($scope.items[i] + 4);
        }

        //clear out items array (starts the leave animation)
        $scope.items = [];

        //wait 1s for leave animation to complete then re-populate the items array
        $timeout(function(){
            $scope.items = newItems;
        }, 1000);

    };
}]);

'Working' hacky demo: jsfiddle

JRulle
  • 7,448
  • 6
  • 39
  • 61