Search code examples
angularangular-materialangular-animationsmat-tab

Angular animations don't work inside mat-tabs after switching back


I'm trying to get a simple :enter/:leave animation to work on a mat-list inside a mat-tab. The initial animation is no problem, the problem occurs when switching to a different tab and returning to the first one. That time the animation doesn't get triggered and the list stays hidden.

It does make sense the list disappears since the content of a tab gets removed from the DOM when you switch to different tabs. Is there a way to keep the content in the DOM or to make sure the animation gets triggered again?

This is my current template and component. I've also made a Stackblitz example.

import { Component } from '@angular/core';
import { trigger, transition, style, sequence, animate} from '@angular/animations';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ],
  animations: [
    trigger('fadeAndSlideTop', [
      transition(':enter', [
        style({opacity: '0', height: '0'}),
        animate('150ms ease-in', style({opacity: '1', height: '*'}))
      ]),
      transition(':leave', [
        animate('150ms ease-out', style({opacity: '0', height: '0'}))
      ])
    ])
  ]
})
export class AppComponent  {
  name = 'Angular';

  list = [
    {id: 1, text: 'Item 1'},
    {id: 2, text: 'Item 2'},
    {id: 3, text: 'Item 3'},
  ]
}
<mat-tab-group dynamicHeight="true">
    <mat-tab label="List">
        <h4>List examples</h4>
        <mat-action-list class="list">
            <button mat-list-item class="list-item" *ngFor="let item of list" [@fadeAndSlideTop]>
        <span>{{item.text}}</span>
        <mat-divider></mat-divider>
      </button>
        </mat-action-list>
    </mat-tab>
    <mat-tab label="Other things">
        <h2>Other things come here</h2>
    </mat-tab>
</mat-tab-group>

https://stackblitz.com/edit/angular-9-material-starter-sqsqgu?file=src/app/app.component.html

ANSWER

So after using the answer of Kavinda Senarathne, I ended up with the template which works perfectly.

<mat-tab-group dynamicHeight="true">
    <mat-tab label="List">
    <ng-template matTabContent>
          <h4>List examples</h4>
          <mat-action-list class="list">
              <button mat-list-item class="list-item" *ngFor="let item of list" [@fadeAndSlideTop]>
          <span>{{item.text}}</span>
          <mat-divider></mat-divider>
        </button>
          </mat-action-list>
    </ng-template>
    </mat-tab>
    <mat-tab label="Other things">
        <h2>Other things come here</h2>
    </mat-tab>
</mat-tab-group>


Solution

  • Try this- the use of directive [matTabContent]

    <mat-tab-group>
      <mat-tab label="First">
        <ng-template matTabContent>
          Content 1 - Loaded: {{getTimeLoaded(1) | date:'medium'}}
        </ng-template>
      </mat-tab>
      <mat-tab label="Second">
        <ng-template matTabContent>
          Content 2 - Loaded: {{getTimeLoaded(2) | date:'medium'}}
        </ng-template>
      </mat-tab>
      <mat-tab label="Third">
        <ng-template matTabContent>
          Content 3 - Loaded: {{getTimeLoaded(3) | date:'medium'}}
        </ng-template>
      </mat-tab>
    </mat-tab-group>