Blackhole
Blackhole

Reputation: 20401

Angular animation on a SVG element

I would like to animate ngRepeat on a SVG element, with Angular 1.2.0rc3, but I can't find the reason why my code doesn't work.

Actually, the following code works perfectly:

<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100">
    <rect ng-repeat="item in itemsList" width="10" height="50" fill="gold" data-ng-attr-x="{{$index*15}}" class="animation" />
</svg>

<div>
    <div ng-repeat="item in itemsList" class="animation">[{{$index}}] {{item}}</div>
</div>
.animation.ng-enter,
.animation.ng-leave
{
    transition-property: opacity;
    transition-duration: 2000ms;
}

.animation.ng-enter.ng-enter-active,
.animation.ng-leave
{
    opacity: 1;
}

.animation.ng-enter,
.animation.ng-leave.ng-leave-active
{
    opacity: 0;
}

Fiddle

But for some mysterious reason, when I put these lines in my real project, the <rect> elements aren't animated anymore. The <div> elements, however, are still animated. And finally, when I manually add the .ng-leave and .ng-leave-active classes on an existing element, with Firebug for instance, i can see the <rect> progressively disappear, as expected. A pretty nice Heisenbug, right?

Notice that I also use jQuery in my project.

Does someone already has encountered a similar issue, or simply has an idea of what is happening?

Upvotes: 2

Views: 2347

Answers (1)

Blackhole
Blackhole

Reputation: 20401

After digging a long time in the source code of my project, AngularJS and jQuery, it appears that the problem comes from jQuery. Indeed, my example works without jQuery but is broken with it.

Let's go deeper: Angular needs to dynamically add classes to the elements in order to animate them. For that purpose, it uses the addClass() method (see the call in the code). The jqLite version of addClass() is simple enough to work on SVG elements in modern browser. That's not the case in the jQuery's one, as shown by this question.

The solution is either, not to use jQuery at all, to use jQuery SVG and his DOM extension, which correct the problem…

<script src="jquery.js"></script>
<script src="jquery.svg.js"></script>
<script src="jquery.svgdom.js"></script>
<script src="angular.js"></script>
<script src="angular-animate.js"></script>

… or simply to use the jqLite version of addClass():

(function($) {
    'use strict';

    $.fn.addClass = function (cssClasses)
    {
        this.each(function ()
        {
            var element = this;
            if (cssClasses && element.setAttribute) {
                var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
                                        .replace(/[\n\t]/g, " ");

                $.each(cssClasses.split(' '), function(i, cssClass) {
                  cssClass = cssClass.trim();
                  if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
                    existingClasses += cssClass + ' ';
                  }
                });

                element.setAttribute('class', existingClasses.trim());
            }
        });

        return this;
    };
})(jQuery);

Upvotes: 8

Related Questions