Angular.js: Parent directive element doesn't wait for child animations to complete before being removed from DOM.

Created on 2 Jun 2015  路  16Comments  路  Source: angular/angular.js

The issue occurs whenever I have at least two custom directives that are toggled by an ng-switch. I listen to the leave event on the directive so that I can transition out some of the child elements before it removes the parent from the DOM and switches to the other directive. NgAnimate is not waiting for the child animations to complete before it removes the parent from the DOM in order to display the other directive in the ng-switch.

This is important because I need to be able to transition out the directive's child elements before the directive is switched. For instance, I have a directive that has an ng-repeat in its template, and I want to stagger animate out all of the elements in that ng-repeat before the entire directive is removed from the DOM.

Angular Version: 1.4.0

The plunker demonstrating the lack of animation on the ng-repeat items is here: http://plnkr.co/edit/uV5PJcVCROPXgSvYUy10

I think that the problem is in the scope of the element. The things in the scope.$apply are not getting called. I have also tried this with the $destroy event on the element and it does the same thing. I am pretty positive this needs to be called in an $apply block or with a $digest following it in order to animate however.

That being said; if animations do perform, then they still need to hold off the parent element's removal and switching until they are completed.

Thanks guys,

ngAnimate low inconvenient feature

Most helpful comment

Is this feature still being added?

All 16 comments

Did this work before 1.4.0?

I never tested before 1.4 so I am not sure honestly

This is getting fixed in the next release for 1.4.2

Great! Thank you guys for your work

Sorry there has been a bit of a delay. It turns out that #12248 doesn't effect this issue. I will be working on this tomorrow.

Alright so looking at this properly now I want to verify what you're trying to do.

You want the outer contain element (in this case the ng-switch-when container) to wait for each of the inner repeat items to finish animating away before it is removed from the DOM yes? This doesn't exist in ngAnimate as of now, however, I think we could add a new property to ng-animate-children:

<div ng-swich-when="..." ng-animate-children="wait">...</div>

In 1.5 we aim to make this a better API, but that's still not concrete. For now this feature could work.

In future versions of Angular we may even have a CSS solution like this:

.switch-container.ng-leave {
   transition:0.5s linear all;
   --ng-animate-children: 'wait';
}
.switch-container.ng-leave.ng-leave-active { ... }

.ng-switch-container .repeat-items.ng-leave { ... }
.ng-switch-container .repeat-items.ng-leave.ng-leave-active { ... }

Yes that is exactly what I am trying to do. That would probably be ok for the time being. Ideally I think it would be great to have it there by default, but its ok if it isn't. It would be nice if the animations could hook into some "you are about ready to be destroyed" event, like the destroy event, and the parent would just have to wait. That way a directive could prepare for that scenario out of the box.

Just a thought,
but I am up for whatever way you guys think it'll work best. I don't know much of the implementation behind ng-Animate.

It does seem like since ngAnimateChildren by default animates the children in, that it should also animate them out before moving though.

What do you think?

I like the css solution much more than the wait parameter. I might be misunderstanding it, but it seems like the css solution would be much more dynamic.

Yes the CSS solution might just be apart of the plan for a future release, but it does require a build system. For now (1.4 and 1.5) we may need to stick with the wait param.

Ok, as long as we can get something that will do the job, changing it later is fine. Thanks @matsko,

Is this feature still being added?

Has this been implemented?

AFAICT, this works in v1.7.4 (so it must have been fixed somewhere along the way).

@gkalpak do you have an example for this? I wonder if this is the behavior we always want, or if it should have been optional.

Sorry, I probably spoke too soon. This doesn't really work exactly as OP requested it.
Playing around with an example, here is what I found out:

  1. ngAnimateChildren explicitly does not apply to leave animations. (This is intended behavior - not sure why 馃槙)
    From the docs:

    Note that even if ngAnimateChildren is set, no child animations will run when the parent element is removed from the DOM (leave animation).

  2. It _is_ possible to have the child animations run. For example, you manually animating them (as in OP's example), with something like:

    $animate.on('leave', parentElem, (eventTarget, phase) => {
      if ((phase === 'start') && (eventTarget[0]=== parentElem[0])) {
        angular.forEach(parentElem.find('p'), p => $animate.leave(p));
      }
    });
    

    But the child animations will not be coordinated with the parent animation. I.e. the parent animation will not wait for child animations to complete before removing the parent element from the DOM. But it is possible to manually coordinate them (e.g. by specifying appropriate animation durations).

The example I used is here.

Was this page helpful?
0 / 5 - 0 ratings