Search code examples
angularangular-materialmat-tab

Strange behavior on mat-tab


I am facing a strange issue with Angular Material Tabs and hope someone can help me explain what is going on. https://stackblitz.com/edit/angular-ivy-yttids

I have a mat-tab component with 3 tabs. My goal is to call an external service as soon as the user clicks on any tab for the first time and display the results in tab contents.

On page initialization, tabs are generated and Tab-1 comes already selected. And if I click tabs in a certain order (Tab3->Tab2-Tab1), everything is just as expected. But if I click Tab2 first, after page refresh, it is not activated but focus passes on Tab-3 automatically for no reason. The behavior repeats just once more on Tab1 and back to normal, meaning I can activate the tab I click.

Here is another strange order of clicks you might want to check yourself:

  1. Tab2 (Passes to Tab3)
  2. Tab2 (Contents are displayed)
  3. Tab1 (Passes to Tab3)
  4. Tab1 (Contents are displayed)
  5. Tab3 (Contents are displayed)
  6. Tab1 (Contents are displayed)
  7. Tab2 (No tab content, although the internal variables are just fine and it was working on step 2 )

I'd appreciate it if you can have a look at the link and let me know if you can figure out what's really going on.

Thanks


Solution

  • Well, you're actually changing the section variable, which is used to render the tab. (inside your *ngFor).

    Changing this section will force mat-tab to reload the component which result in a funny bug (sorry, cannot explain better than that).

    My option is to add a trackBy function, so you tell angular to only reload the element that did changed.

    There the solution in a stackblirtz

    1. Add the trackBy function into your .component.ts
     trackByIndexFn(index: any, item: any) {
        return index
      }
    
    1. Then into your .component.html
    <div *ngIf="input">
      <mat-tab-group
        #tabs
        mat-align-tabs="center"
        animationDuration="0ms"
        [(selectedIndex)]="selectedIndexBinding"
        (selectedIndexChange)="onTabChanged($event)"
      >
        <mat-tab
          *ngFor="let section of parts; index as tabNo; trackBy: trackByIndexFn" <!-- Here, I use the trackBy function -->
        >
          <ng-template mat-tab-label>
            <span class="tab-heading">Tab {{ tabNo + 1 }}</span>
          </ng-template>
          <ng-template matTabContent>
            <br />
            <div *ngFor="let data of section; index as i">
              <div style="text-align:center">{{ data }}</div>
              <br />
            </div>
          </ng-template>
        </mat-tab>
      </mat-tab-group>
    </div>
    
    

    you're not only avoiding the bug, but also optimizing your code ;)