10

I want to use Angular Material tabs https://material.angular.io/components/tabs with a router navigation in the tabs.

I tried to use <nav mat-tab-nav-bar> as indicated in the doc, and I found this tutorial: https://nirajsonawane.github.io/2018/10/27/Angular-Material-Tabs-with-Router/ where I can find a template like that:

<nav mat-tab-nav-bar>
  <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>

But the problem is, that my tabs are not at the root of my application, but are in a submodule in a child route. I have something like that:

In app-routing-module:

const routes: Routes = [
  ...
  { path: 'subpath', loadChildren: () => import('./path-to-module/submodule.module').then(m => m.SubmoduleModule) },
  ...
];

In submodule-routing-module I should have something like that:

const routes: Routes = [
  { path: '', component: FirstTabComponent },
  { path: 'tab2', component: SecondTabComponent },
]

What I would like is that, if I go to url /subpath I see the tabs with the first tab selected, and if I go to url /subpath/tab2 I see the tabs with the second tab selected.

Any idea how to do that?

3
  • Did you find a way to solve this? Commented Feb 7, 2020 at 10:38
  • Not really... I used a workaround, not using the Angular router but managing the tab's routes manually... Commented Feb 8, 2020 at 17:15
  • @S.Caruso Does the answer of janders meet your requirements? stackoverflow.com/a/60367203/1065654 Commented Nov 6, 2021 at 14:25

5 Answers 5

14

I, too, ran into the same issue. I cloned Angular-Material-Tabs-with-Router but modified it with a child component that also has child components.

The child component is called home and in home.component.html it implements:

<nav mat-tab-nav-bar>
  <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>

This creates 3 tabs called Notes, Photos and Documents. The Notes tab includes additional components to list, view, edit and delete notes.

I created and added the source to GitHub and imported it to Stackblitz:

GitHub

Stackblitz

Sign up to request clarification or add additional context in comments.

2 Comments

OP wanted the first tab selected when not in a child of the tabs page which your example does not do. I just threw a this.router.navigate(['subPathToFirstTab'], { relativeTo: this.route }); at the end of ngOnInit and it works nicely. (Injecting private route: ActivatedRoute in the constructor.)
@StackUnderflow Good catch, but your solution has a bug. If you open another link directly (e.g. click on the second tab and reload the page), you get navigated to the first link/tab. However, you should stay at the child of the tabs page in this case (in my example the second tab).
4

An alternative to janders solution is to use the router dependency. With router.url()function, you are able to compare the current active url with your navigation links.

In your Component.ts:

...

rootUrl = '/path/to/your/component';

  navigation = [
    {
      name: 'Table',
      link: '',
    },
    {
      name: 'Stats',
      link: '/stats',
    },
    {
      name: 'Settings',
      link: '/settings',
    },
    {
      name: 'Export',
      link: '/export',
    }
  ];

constructor(private route: ActivatedRoute, public router: Router) {
...
}

...

In your Component.html:

...

  <nav mat-tab-nav-bar mat-align-tabs="left">
    <a mat-tab-link
       *ngFor="let l of navigation"
       [routerLink]="rootUrl + l.link"
       [active]="this.router.url === rootUrl + l.link">
      {{l.name}}
    </a>
  </nav>

...

In your router:


...

  {
    path: '/path/to/your/component',
    component: Component,
    canActivate: [AuthGuard],
    children: [
      {
        path:'',
        pathMatch: 'full',
        component: TableComponent
      },
      {
        path:'settings',
        pathMatch: 'full',
        component: SettingsComponent
      },
      {
        path:'export',
        pathMatch: 'full',
        component: ExportComponent
      },
      {
        path:'stats',
        pathMatch: 'full',
        component: StatsComponent
      }
    ]
  }

...

Comments

3

If my understanding is right, you want to navigate to a component in a lazy loaded module.

For this I made a stackblitz, which might be useful for you.

Here's the basic code for your understanding

<nav mat-tab-nav-bar class="mat-elevation-z8" >
  <a
    mat-tab-link
    *ngFor="let link of navLinks"
    routerLink="{{ link.location }}"
    routerLinkActive
    #rla="routerLinkActive"
    [active]="rla.isActive"
  >
    <mat-icon>{{ link.icon }}</mat-icon>
    <span>{{ link.label | uppercase }}</span>
  </a>
</nav>

in ts

 navLinks = [
    {location:'',label:'dummy',icon:'menu'},
    { location: '/shared', label: 'Overview', icon: 'account_circle' },
    { location: '/shared/sub', label: 'Experience', icon: 'work' }
  ];

Stackblitz

3 Comments

Hello, your stackblitz seems not to have anything to do with material tabs... Is it the correct one?
Updated stckblitz link, check once
Thanks, the stackblitz is the right one now. But infortunately this doesn't meet my needs: my tabs component should also be in the lazy loaded module, not in the root module...
3

I had the same issue. The problem came from the routing module.

In order to inherit the imported Material classes, the path for children must be lazy-loaded instead of being directed from the component.

This caused the problem:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';


const routes: Routes = [
  {
    path: 'customers',
    // Don't use this method in order to link to children!
    component: 'CustomerListComponent'

  } 

The 'customer list' template loaded, but without formatting. Also, Angular threw an error because it could not find the 'mat-tab' directive anywhere, even though it was being imported in the parent component, orders.module.ts.

This was the solution: src > app > app-routing.module.ts

const routes: Routes = [{
      path: 'customers',
      loadChildren: () =>
        import ('./customers/customers.module').then(m => m.CustomersModule)
    }

Here are the related files from the project: src > app > orders > orders.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { OrdersRoutingModule } from './orders-routing.module';
import { OrderListComponent } from './order-list/order-list.component';

// Material components
import { MatTabsModule } from '@angular/material/tabs';

@NgModule({
  imports: [
    CommonModule,
    OrdersRoutingModule,
    MatTabsModule
  ],
  declarations: [
    OrderListComponent
  ]
})
export class OrdersModule { }

src > app > orders > orders-list > orders-list.component.html

<mat-tab-group>
  <mat-tab label="Orders">
    <ng-template matTabContent>
      <p>Orders here.</p>
    </ng-template>
  </mat-tab>
  <mat-tab label="Shipments">
    <ng-template matTabContent>
      <p>Shipments here.</p>
    </ng-template>
  </mat-tab>
  <mat-tab label="Archived">
    <ng-template matTabContent>
      <p>Really old orders here.</p>
    </ng-template>
  </mat-tab>
</mat-tab-group>

1 Comment

This is regular tab implementation. OP asked for routed tabs though.
0

the same code previously see, but updated

************* code updated ********  (12-05-2022, version angular recent)
              <nav mat-tab-nav-bar >
                      <a mat-tab-link *ngFor="let link of navLinks"
                               (click)="activeLink = link.link"
                               [routerLink]="link.link"
                               [active]="activeLink == link.link"> {{link.label}} </a>
                    </nav>
              <router-outlet></router-outlet>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.