7

The project presents two variants of animation.

Animation Option 1, trigger('animationOption1')
Works without complaints.

Animation Option 2, trigger('animationOption2')
transition doesn't work here.

Online check this project in StackBlitz.com

app.component.html

<h1>Animation Option 1</h1>
<div (click)="changeDivState()"
     [@animationOption1]="clickedDivState"
>Click Me
</div>

<h1>Animation Option 2</h1>
<button (click)="toggleMenu()">Click Me</button>
<ul *ngIf="isMenuOpen"
    [@animationOption2]="isMenuOpen ? 'open': 'close'"
>
  <li>Menu Item 1</li>
  <li>Menu Item 2</li>
  <li>Menu Item 3</li>
</ul>

app.component.ts

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  animations: [
    trigger('animationOption1', [
      state('start', style({
        backgroundColor: 'yellow',
        width: '150px',
        height: '150px'
      })),
      state('end', style({
        backgroundColor: 'green',
        width: '300px',
        height: '300px'
      })),
      transition('start => end', animate(1500)),
      transition('end => start', animate('800ms 0.5s ease-out'))
    ]),
    trigger('animationOption2', [
      state('close', style({
        opacity: 0,
        backgroundColor: 'yellow'
      })),
      state('open', style({
        opacity: 1,
        backgroundColor: 'green'
      })),
      transition('close <=> open', animate(3000)),
    ])
  ]
})
export class AppComponent {
  isMenuOpen = false;

  clickedDivState = 'start';

  changeDivState() {
    this.clickedDivState = 'end';
    setTimeout(() => {
      this.clickedDivState = 'start';
    }, 3000);
  }

  toggleMenu(): void {
    this.isMenuOpen = !this.isMenuOpen;
  }
}

Googling did not lead to a solution.

ZoomAll
  • 423
  • 1
  • 6
  • 10

1 Answers1

18

To get this to work you will need to remove the *ngIf="isMenuOpen" on the <ul>. Angular is unable to calculate the transition between the closed/open states as the element simply does not exist when isMenuOpen is false.

Here is a StackBlitz showing the animation in action with *ngIf removed.

Alternatively you can utilize entering/leaving states to use in conjunction with *ngIf. It would look like this:

trigger('animationOption2', [      
  transition(':enter', [
    style({ backgroundColor: 'yellow' }),
    animate(300)
  ]),
  transition(':leave', [
    animate(300, style({ backgroundColor: 'yellow' }))
  ]),
  state('*', style({ backgroundColor: 'green' })),
])

Here is a StackBlitz in action.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Alexander Staroselsky
  • 37,209
  • 15
  • 79
  • 91
  • Yes, thank you, Alexander! However, the list remains in the document flow when you solve it, but it is easily corrected by adding the 'display' property with the corresponding values for the States. – ZoomAll May 11 '18 at 21:53
  • If you need to remove it from the document flow, you can actually `:enter` and `:leave` transitions. You can then use `*ngIf`. Check out this [question](https://stackoverflow.com/questions/36417931/angular-2-ngif-and-css-transition-animation) – Alexander Staroselsky May 11 '18 at 21:57
  • You can also use the `:enter` and `:leave` transitions – Ploppy May 11 '18 at 21:57
  • Damn it, now understandable for what need these [":enter" and ":leave"](https://angular.io/api/animations/transition#using-enter-and-leave), thanks – ZoomAll May 11 '18 at 22:08
  • @AlexanderStaroselsky I have used mentioned solution but time i am passing isn't working. Its just hide/show immediately like *ngIf default. Any idea what can be wrong? – Akash Jain May 17 '19 at 06:46
  • @AkashJain You should create a new question to get the best possible support for your issue. – Alexander Staroselsky May 17 '19 at 13:20