Search code examples
javascriptjqueryangularjsng-animate

ng-leave animation doesn't work after height of div is modified


I've got several divs stacked up using ng-repeat, and I'm using ng-leave so that when a div is deleted, it's height transitions to 0px.

This all works fine.

However, I'm encountering difficulty when I modify the height of a div at any point before I delete it. For example if I click the "Animate Height" button on a div, then try to delete it, the ng-leave animation won't run--it simply waits 1s before disappearing.

FIDDLE: https://jsfiddle.net/c1huchuz/32/

HTML:

<body ng-app="myApp" ng-controller="myController">
    <button ng-click="add_div()">Add Div</button>
    <div id="wrapper">
        <div ng-repeat="x in random_array" class="slide">               
            {{$index}}
            <button ng-click="remove_div($index)">Delete</button>
            <button ng-click="change_size($index)">Animate Height</button>
        </div>
    </div>
</body>

CSS:

.slide {
  position: relative;
  width: 160px;
  height: 30px;
  background-color: orange;
  border: 1px solid black;
}

.slide.ng-enter {
  transition: all 1s;
  top: -30px;
  z-index: -1; 
}

.slide.ng-enter.ng-enter-active {
  top: 0px;
  z-index: -1; 
}

.slide.ng-leave {
  transition: all 1s;
  height: 30px;
  z-index: -1; 
}


.slide.ng-leave.ng-leave-active {
  height: 0px;  
  z-index: -1; 
}

JS:

var app = angular.module("myApp", ['ngAnimate']);
app.controller("myController", ["$scope", function($scope) {
    $scope.random_array = []
    $scope.add_div = function() {
        var x = $scope.random_array.length
        $scope.random_array.push(x)
    }
    $scope.remove_div = function(index) {
        $scope.random_array.splice(index, 1)
    }
    $scope.animate_height = function(index) {
        $(".slide:nth-child("+(index+1)+")").animate({"height":"60px"}, 1000).animate({"height":"30px"}, 1000)    
    }
}]);

Solution

  • After playing around some, I discovered that the issue is not specific to angularJS or ng-animate.

    The issue is actually one of CSS precedence. .animate() adds an inline style attribute to the affected div, so when I animate a div, it is left with this style attribute set to a height of 30px. Because inline style has a higher CSS precedence than a class, the .ng-leave and .ng-leave.ng-leave-active don't affect the divs height when added.

    A good read on CSS precedence: http://vanseodesign.com/css/css-specificity-inheritance-cascaade/

    To fix the issue, I remove the style attribute of a div before removing the div itself:

    $scope.remove_div = function(index) {
        $(".slide:nth-child("+(index+1)+")").removeAttr("style") //added this line
        $scope.random_array.splice(index, 1)
    }