Ng-view with ng-animate executes directive twice

advertisements

while i was playing with ng-view and ng-animate from angularjs 1.1.4, i noticed that directives are executed twice. once for the element in the view that enters the screen and again for the element in the view which leaves the screen (while the directive was already executed for the element when the view entered the screen).

for my understanding, directives should only be executed for elements which enter the screen and not for the ones which leaves. or am i missing something?

<div ng-app="app">
    <div ng-controller="AppCtrl">
        <div class="btn-group">
            <a class="btn btn-primary" href="./">foo</a>
            <a class="btn btn-primary" href="bar/">bar</a>
        </div>
        <span class="btn btn-success">{{count}}</span>
        <div class="view" ng-view ng-animate="{enter: 'view-enter', leave: 'view-leave'}"></div>
    </div>
</div>

var app = angular.module('app', []);

app.config(function ($routeProvider, $locationProvider) {
    $routeProvider
        .when('/', {
            template: '<h1 color>foo</h1>'
        })
        .when('/bar', {
            template: '<h1 color>bar</h1>'
        })
        .otherwise({
            redirectTo: '/'
        });

    $locationProvider.html5Mode(true);
});

app.controller('AppCtrl', function ($scope) {
    $scope.count = 0;
    $scope.incrementCount = function () {
        $scope.count++;
    }
});

app.directive('color', function () {
    return {
        restrict: 'A',
        link: function ($scope, $element, $attrs) {
            // executed once the app inits but
            // twice when you change the view
            $scope.incrementCount();
        }
    }
});

i've setup a jsfiddle for this http://jsfiddle.net/mediastuttgart/f4FPj/1/

as you can see, the counter says 1 when the app inits. but if you start navigating, the counter increments by 2.

cheers michael

EDIT

of course a workaround could be to add a class to the element and check for it in the directive – but i guess that's not the way it should be accomplished.

link: function ($scope, $element, $attrs) {
    if ($element.hasClass('processed')) return;
    $element.addClass('processed');
    $scope.incrementCount();
}

http://jsfiddle.net/mediastuttgart/f4FPj/2/


It's going to fire the directive for each event that directive handles. See this fiddle, if you remove the leave event, it only fires once.

<div class="view" ng-view ng-animate="{enter: 'view-enter'}"></div>

http://jsfiddle.net/WmSP8/1/

Notice the documentation says "The event1 and event2 attributes refer to the animation events specific to the directive that has been assigned."(http://code.angularjs.org/1.1.4/docs/api/ng.directive:ngAnimate)

It's essentially saying that you can build directives with custom events not present in all directives, and the animator service will allow your directive to know which animations to run when these events fire in your directive. However this means your directive can possibly execute for each event handled in your ng-animate attribute. So when you configure both the enter and leave, the directive executes for them both.

I haven't actually written any code to test this, this is just my interpretation of the documentation, and the jsfiddle seems to confirm the general premise.