angular: [Animation] In Angular4, leave (* -> void) animation doesn't fire when element is destroyed by ngIf value change

I’m submitting a … (check one with “x”)

[x] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior

I have a component with an ngIf. When the ngIf is set to true, the enter animation (void -> *) fires. When the ngIf is set to false, the leave animation (*->void) doesn’t fire.

Expected behavior

I would expect, when the ngIf is set to false, that the leave animation for the component would fire as it used to in 2.4.x: https://plnkr.co/edit/YmxInnbLmXRYrc4onrEd

Minimal reproduction of the problem with instructions

This is the same code in 4.0.1, where the leave animation doesn’t fire: http://plnkr.co/edit/i4PMM9XyuiEzSdfEgWO6

What is the motivation / use case for changing the behavior?

Consistency for enter/leave animation for component created/destroyed by ngIf.

Please tell us about your environment:

  • Angular version: 4.0.1
  • Browser: all
  • Language: TypeScript 2.2

  • Node (for AoT issues): node --version = 6.9.0

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 14
  • Comments: 31 (8 by maintainers)

Most upvoted comments

Hey @matsko

Unfortunately your example doesn’t work if the @easeInOut animation is inside another component (instead of the same component with a parent @ngIfAnimation.

The :enter transition always fires correctly, but the :leave (or * => void) transition never fires (it’s just immediately removed).

I edited your plunker to show you what I (and others) are running into, even with the latest 5.0.0-beta.0: https://plnkr.co/edit/o5gSwIbAEB6daKHZUxVs?p=preview

Alright so it turns out that this can’t be fixed in a similar manner to how it worked in NG2. The reason being is because a parent node, in Angular 4, always has priority in animation land. So if inner animations exist in a parent ngIf and the ngIf has no animation then it will always be removed immediately and the inner animation will be skipped.

There is however a way to make this work using the new query() and animateChild() features.

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <button (click)="toggle()">Toggle</button>
      <div *ngIf="show" @ngIfAnimation>
        <h3 @easeInOut>I'm inside ngIf</h3>
      </div>
    </div>
  `,
animations: [
  trigger('ngIfAnimation', [
    transition(':enter, :leave', [
      query('@*', animateChild())
    ])
  ])
  //...
]
})
class App {...}

Here is this working on RC2: https://plnkr.co/edit/RJgAunJfibBKNFt0DCZS?p=preview

I’m sure the new features outlined above make the animation a lot more exciting 😃

This will be fixed in the first 4.2 beta.

v 4.2.6 and I have the same problem 😦

i don’t need animateChild() and it works now:

 animations: [
    trigger('easeInOut', [
      transition(':enter', [
        style({
          opacity: 0
        }),
        animate("1s ease-in-out", style({
          opacity: 1
        }))
      ]),
      transition(':leave', [
        style({
          opacity: 1
        }),
        animate("1s ease-in-out", style({
          opacity: 0
        }))
      ])
    ])
  ]

and in template :

<button (click)="show= !show">go!</button>
<p *ngIf="show"  @easeInOut>hello world</p>

this is awesome! 😃

This was just fixed @staeke 😉

See #18305

Issue still present in 5.0.0-beta.5. updated plunker

Can you please take a look @matsko ? Thanks!

Sorry that this change came up so abruptly. It was something that was planned for 4.0.0, but due to complexities in the new features it got pushed until later and then the fix got lost in the mix of the 4.1/4.2 releases.

Once final 4.2 lands and the animation guide comes out then it will contain clear info about how all this new stuff works. Thank you guys for keeping this issue up to date.

@istiti yep, 5.0.0-rc.3 recently released with the fix 🍺

Note: you have to use the newer syntax though for it to work (i.e. query(), animateChild() etc - see above example!)

Actually I was able to resolve my issue using trackBy with my ngFor.