'How to implement routed tabs with angular material, within a child route?
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?
Solution 1:[1]
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:
Solution 2:[2]
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>
Solution 3:[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' }
];
Solution 4:[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
}
]
}
...
Solution 5:[5]
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>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Treycos |
Solution 3 | Dharman |
Solution 4 | Seb |
Solution 5 | lura_river |