Skip to main content
Ben Nadel at InVision In Real Life (IRL) 2018 (Hollywood, CA) with: Mike Frey
Ben Nadel at InVision In Real Life (IRL) 2018 (Hollywood, CA) with: Mike Frey ( @mikefrey )

Possible Bug With Nested Animation Transitions In Angular 2 RC 6

By on

As I've been digging into the animation support in Angular 2 RC 6, I think I have come across a bug. From what I can see, it appears that if a dynamic container has more than one nested animation attached to static elements, the container is not destroyed at the end of the transition. If there is only one nested animation, things work fine; but, once you go beyond a single nested transition, the process appears to break down.

Run this demo in my JavaScript Demos project on GitHub.

To demonstrate this, I've created a small demo in which two containers are swapped using ngSwitch / ngSwitchCase directives. Inside each container, there are two boxes. As the containers are swapped, each of the descendant boxes animates vertically. If the first box is animated, all goes well. If the second box is animated, all goes well. But, if both boxes are animated, the container is never destroyed.

Well, sort of. If you remove the "container" animation, the bug becomes slightly different, symptomatically. It appears that you can have a single nested animation as long as the container isn't animated. If the container itself is animated, you can't have any nested transitions.... To be honest, the buggy behavior itself it kind of hard to articulate - watch the video to see what I mean.

// Import the core angular services.
import { animate } from "@angular/core";
import { Component } from "@angular/core";
import { state } from "@angular/core";
import { style } from "@angular/core";
import { transition } from "@angular/core";
import { trigger } from "@angular/core";

@Component({
	selector: "my-app",
	animations: [
		// The container doesn't technically have any animation; but, it feels "weird" to
		// try an animate the nested elements without also having a transition on the
		// actually-dynamic container element.
		// --
		// NOTE: The animations work all the same without this container-animation; this
		// is here for my own peace of mind.
		trigger(
			"containerAnimation",
			[
				transition(
					"void => * , * => void",
					animate( "1000ms" )
				)
			]
		),

		// As the container is swapped-in, Box A will come in from the bottom.
		trigger(
			"boxOneAnimation",
			[
				state(
					"void",
					style({
						top: "100%",
						opacity: 0.0,
						transform: "rotate( 1000deg )"
					})
				),
				state(
					"*",
					style({
						top: "50%",
						opacity: 1.0,
						transform: "rotate( 0deg )"
					})
				),
				transition(
					"void => * , * => void",
					animate( "1000ms ease-in-out" )
				)
			]
		),

		// As the container is swapped-in, Box B will come in from the top.
		trigger(
			"boxTwoAnimation",
			[
				state(
					"void",
					style({
						top: "-10%",
						opacity: 0.0,
						transform: "rotate( 1000deg )"
					})
				),
				state(
					"*",
					style({
						top: "50%",
						opacity: 1.0,
						transform: "rotate( 0deg )"
					})
				),
				transition(
					"void => * , * => void",
					animate( "1000ms ease-in-out" )
				)
			]
		)
	],
	template:
	`
		<p>
			<a (click)="showContainer( 'a' )">Show Container A</a>
			&mdash;
			<a (click)="showContainer( 'b' )">Show Container B</a>
		</p>

		<div [ngSwitch]="activeContainer" class="viewport">

			<div *ngSwitchCase=" 'a' " @containerAnimation class="container">
				<div class="label">
					Container A
				</div>
				<div @boxOneAnimation class="box-one">
					Box One
				</div>
				<div @boxTwoAnimation class="box-two">
					Box Two
				</div>
			</div>

			<div *ngSwitchCase=" 'b' " @containerAnimation class="container">
				<div class="label">
					Container B
				</div>
				<div @boxOneAnimation class="box-one">
					Box One
				</div>
				<div @boxTwoAnimation class="box-two">
					Box Two
				</div>
			</div>

		</div>
	`
})
export class AppComponent {

	public activeContainer: string;


	// I initialize the component.
	constructor() {

		this.activeContainer = "a";

	}


	// ---
	// PUBLIC METHODS.
	// ---


	// I show the given container.
	public showContainer( container: string ) : void {

		this.activeContainer = container;

	}

}

As you can see, "Box A" animates up from the bottom and "Box B" animates down from the top. I've also attached a non-visual transition to the container itself because it feels "funny" to animate nested elements without explicitly adding a transition to the container itself. But, to be clear, the transition on the container doesn't appear to be necessary. That said, the existence of the container animation changes the symptoms of the bug slightly.

When we run this code, and try to swap out the containers, we get the following output:

Possible bug using nested animations on static elements in Angular 2 RC 6.

As you can see, the container elements are not getting destroyed.

One thing to note here is that the nested animations are on non-dynamic elements (ie, elements that are not controlled by structural directives). If I go and add *ngIf="true" to the nested Box animations to have them be superficially controlled by structural directives, the bug goes away. So, it seems that this buggy behavior is directly related to using nested animations on static elements.

I'm pretty sure this is a bug. That said, I'm basically on day-three of learning Animations in Angular 2 RC 6; so, it's quite possible I am just missing something. It's also possible that animations weren't intended to work with static elements? I'm not really sure. But, it seems this would be necessary to implement proper animation support.

Want to use code from this post? Check out the license.

Reader Comments

27 Comments

I recommend you post this to:
https://gitter.im/angular/angular
specifically to @alxhub (I posted to him as well, he is one of the ng2 gurus)

in any case I am not sure if are familiar with gitter site, but it is THE place to ask Q's on ng2, like this post!

Regards

15,663 Comments

@Sean,

I've tried posting to the Gitter channel a few times in the past and never got any replies to my questions :) I think asynchronous chat rooms are hard for stuff like this - you have to keep going back and scrolling through loads of messages to see if anyone is referring to your question. It's tough.

15,663 Comments

@All,

I think there was actually *more* buggyness here than I realized. I am working on a quick follow-up to just point out the other half of what I found. And, the *ngIf hack that I thought worked does not work for this. So, there may be no viable work-around for this bug at this point.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel