Angular 2 Void Animations Don't Fire On Remove

1.3k Views Asked by At

How do I get animations to fire on removal of a dom element in Angular2?

import { Component, Input, Output, EventEmitter } from '@angular/core';
import { FormGroup, FormControl, Validators } from "@angular/forms";

import {
  trigger,
  state,
  style,
  animate,
  transition
} from '@angular/animations';

import { ServerService } from './server.service';

@Component({
  selector: 'fc-server',
  templateUrl: './server.component.html',
  animations: [
  trigger('flyInFlyOut', [
    state('*', style({transform: 'translateX(0)', opacity: 1})),
    transition('void => *', [
      style({transform: 'translateX(-100%)', opacity: 0}),
      animate('400ms ease')
    ]),
    transition('* => void', [
      style({transform: 'translateX(-100%)'}),
      animate('400ms ease')
    ])
  ])
  ]
})
export class Server {

  @Input() serverInstance;

  serverForm;

  constructor(
    private serverService: ServerService) {}

  ngOnInit() {
    this.serverForm = new FormGroup({
      serverName: new FormControl('', Validators.required),
      serverPort: new FormControl('', Validators.required),
      serverIp: new FormControl('', Validators.required),
    });
  }


  @Output() remove = new EventEmitter();

  onRemove() {
    this.serverService.remove(this.serverInstance);
  }

  onSubmit(serverInstance) {
    this.serverService.add(serverInstance);
  }
}

Everything works, removal of the item from the list, adding items to the list, animation in...except when an item is removed, the list item is deleted with no animation. Any insight?

It seems like a reoccurring issue with Angular2, however nobody really has a good resolution as far as I've seen.

For instance, this article: https://www.bennadel.com/blog/3140-using-changedetection-with-animation-to-setup-dynamic-void-transitions-in-angular-2-rc-6.htm

2

There are 2 best solutions below

1
kyw On

You need to define the end state of your void too:

state('void', style({transform: 'translateX(100%)', opacity: 0}))

Then removes the style({transform: 'translateX(-100%)'}), line in your * => void transition.

Or I would write it in , in my opinion, an easier form to understand:

trigger('flyInFlyOut', [
  transition(':enter', [
    // the element receives this style immediately and then animates to the 
    // next style which is the `style({ transform: 'translateX(0)', opacity: 1 })`
    style({ transform: 'translateX(-100%)', opacity: 0 }),
    animate('300ms', style({ transform: 'translateX(0)', opacity: 1 })),
  ]),
  transition(':leave', [
    style({ transform: 'translateX(0)', opacity: 1 }),
    animate('200ms', style({ transform: 'translateX(100%)', opacity: 0 })),
  ]),
]);

The :leave and :enter are shorthand for * => void and void => *, respectively.

0
ThonyRG On

I don't know if you still need a solution but you can set the animation to host as true and for cleaner code you can define the style for void state and not * (default), angular is smart enough to know how the final styling should look like, for example:

@Component({
  selector: 'fc-server',
  templateUrl: './server.component.html',
  animations: [
  trigger('flyInFlyOut', [
    state('void', style({transform: 'translateX(-100%)', opacity: 0})),
    transition('void => *', [
      animate('400ms ease')
    ]),
    transition('* => void', [
      animate('400ms ease')
    ])
  ])
  ],
  host: {
    '[@flyInFlyOut]': 'true'
  }
})

Also, if you want to use alias for (void => ) and ( => void) transitions, they are (:enter) and (:leave) respectively as mentioned in another answer.

I was having this exactly same issue and have found this solution. Hope it helps. :)