angularangular-material

Angular 15.1 mat-tab-nav-bar require TabPanel


I recently upgraded my project to Angular 15.1 and noticed a new problem.

On a page I have a mat-tab-nav which opene subpages via routing:

<nav mat-tab-nav-bar color="primary">
  <a mat-tab-link *ngFor="let link of navLinks" [routerLink]="link.link" routerLinkActive #rla="routerLinkActive" [active]="rla.isActive">{{link.label}}< /a>
</nav>
<router-outlet></router-outlet>

After the update everything works fine but in the console I see the error "A mat-tab-nav-panel must be specified via [tabPanel]."

Looking at the Angular code (line 385) https://github.com/angular/components/blob/main/src/material/tabs/tab-nav-bar/tab-nav-bar.ts I see the code:

override ngAfterViewInit() {
 if (!this.tabPanel && (typeof ngDevMode === 'undefined' || ngDevMode)) {
   throw new Error('A mat-tab-nav-panel must be specified via [tabPanel].');
 }
 super.ngAfterViewInit();
}

From the documentation (https://material.angular.io/components/tabs/api tabPanel) it looks like the tabPanel may be null:

tabPanel: associated tab panel controlled by the nav bar. If not provided, then the nav bar follows the ARIA link / navigation landmark pattern. If provided, it follows the ARIA tabs design pattern.

I fixed it by adding a useless mat-tab-nav-panel to my code:

<nav mat-tab-nav-bar color="primary" [tabPanel]="tabPanel">
  <a mat-tab-link *ngFor="let link of navLinks" [routerLink]="link.link" routerLinkActive #rla="routerLinkActive" [active]="rla.isActive">{{link.label}}< /a>
</nav>
<mat-tab-nav-panel #tabPanel></mat-tab-nav-panel>
<router-outlet></router-outlet>

Is this the correct way? It seems to me a bug of the Angular component. What do you think?


Solution

  • In my Opinion you have to wrap the Router Outlet in an <mat-tab-nav-panel>:

    <nav mat-tab-nav-bar color="primary" [tabPanel]="tabPanel">
      <a mat-tab-link *ngFor="let link of navLinks" [routerLink]="link.link" routerLinkActive #rla="routerLinkActive" [active]="rla.isActive">{{link.label}}< /a>
    </nav>
    <mat-tab-nav-panel #tabPanel>
      <router-outlet></router-outlet>
    </mat-tab-nav-panel>
    

    The Documentaton states
    "The corresponding <router-outlet> must be wrapped in an <mat-tab-nav-panel> component and should typically be placed relatively close to the mat-tab-nav-bar (see Accessibility)."
    see Angular Material Tabs: Tabs and navigation
    Although the code example from Angular Team is currently missing the Router-Outlet.