Angular Animation Directives

by dj_straycat

HTML

<script src="http://code.angularjs.org/1.0.0rc9/angular-1.0.0rc9.js"></script>
<div ng-controller="MainTest" ng-cloak>

    <div ng-repeat="item in testArray" animate-in animate-out>
        <input ng-model="item.name" />
        <button ng-click="remove(item)">Remove</button>        
    </div>
    
    <button ng-click="add()">Add</button>
    <hr>
    <pre ng-bind="testArray|json"</pre>

</div>

CSS

body { padding: 10px; }

JavaScript

angular.module('local', [])
    .directive('animateOut', function() {
    var defaultAnimation = function(callback) {
        this.animate({opacity: 0, height: 0}, 300, callback);
    }
    return {
        restrict: 'A',
        inject: { animateOut: 'accessor' },
        priority: 50,
        link: function($scope, ele, attrs) {
            if (!attrs.ngRepeat) return;
            var match = attrs.ngRepeat.match(/^\s*(.+)\s+in\s+(.*)\s*$/),
                item, collection;
            
            $scope.parentEle = ele.parent();
            
            item = match[1];
            collection = match[2];
            
            $scope.collection = function() { return $scope.$eval(collection); }
            
            $scope.$watch($scope.collection, function(val) {
                $.isArray(val)&&(val.animatedRemove = function(item, callback) {
                    var self = this,
                        i = this.indexOf(item);
                    var ele = $scope.parentEle.children('.ng-scope:eq('+i+')'); 
                    
                    $scope.animateOutFN.call(ele, function() {
                        self.splice(self.indexOf(item), 1); 
                        $scope.$apply(); 
                        callback&&callback();
                    })
            });
            })

           
        },
        controller: function($scope, animateOut) {
            $scope.animateOutFN = animateOut()||defaultAnimation;
        }
    }
})

.directive('animateIn', function() {
    var defaultAnimation = function() { 
        this.css({ opacity: 0}).animate({opacity: 1}, 300);
    }
    return {
        restrict: 'A',
        inject: { animateIn: 'accessor' },
        link: function($scope, ele, attrs) {
            $scope.animateInFN.apply(ele);
        },
        controller: function($scope, animateIn) {
            $scope.animateInFN = animateIn()||defaultAnimation;
        }
    }
});



function MainTest($scope) {
    $scope.testArray = [];
   ...