Skip to content

Commit 1f07121

Browse files
authored
fix(module:tabs): update active router tab after tabs changed (#7649)
1 parent 94bab3e commit 1f07121

3 files changed

Lines changed: 146 additions & 9 deletions

File tree

components/tabs/demo/link-router.ts

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import { Component } from '@angular/core';
2-
import { RouterLink } from '@angular/router';
2+
import { Params, RouterLink } from '@angular/router';
33

4+
import { NzButtonModule } from 'ng-zorro-antd/button';
45
import { NzTabsModule } from 'ng-zorro-antd/tabs';
56

67
@Component({
78
selector: 'nz-demo-tabs-link-router',
8-
imports: [RouterLink, NzTabsModule],
9+
imports: [RouterLink, NzTabsModule, NzButtonModule],
910
template: `
11+
<div style="margin-bottom: 16px;">
12+
<button nz-button (click)="newTab()">ADD</button>
13+
</div>
1014
<nz-tabset nzLinkRouter>
1115
<nz-tab>
1216
<a *nzTabLink nz-tab-link [routerLink]="['.']" [queryParams]="{ tab: 'one' }" queryParamsHandling="merge">
@@ -32,7 +36,40 @@ import { NzTabsModule } from 'ng-zorro-antd/tabs';
3236
</a>
3337
Four.
3438
</nz-tab>
39+
@for (tab of dynamicTabs; track tab.title) {
40+
<nz-tab>
41+
<a
42+
*nzTabLink
43+
nz-tab-link
44+
[routerLink]="tab.routerLink"
45+
[queryParams]="tab.queryParams ?? {}"
46+
queryParamsHandling="merge"
47+
>
48+
{{ tab.title }}
49+
</a>
50+
{{ tab.content }}
51+
</nz-tab>
52+
}
3553
</nz-tabset>
3654
`
3755
})
38-
export class NzDemoTabsLinkRouterComponent {}
56+
export class NzDemoTabsLinkRouterComponent {
57+
dynamicTabs: Array<{ title: string; content: string; queryParams?: Params; routerLink: string[] }> = [];
58+
59+
newTab(): void {
60+
const { length } = this.dynamicTabs;
61+
const newTabId = length + 1;
62+
const title = `NewTab${newTabId}`;
63+
this.dynamicTabs = [
64+
...this.dynamicTabs,
65+
{
66+
title,
67+
content: title,
68+
routerLink: ['.'],
69+
queryParams: {
70+
tab: newTabId
71+
}
72+
}
73+
];
74+
}
75+
}

components/tabs/tabset.component.spec.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,66 @@ describe('NzTabSet', () => {
879879
expect(element.querySelectorAll('.ant-tabs-tabpane').length).toBe(1);
880880
}));
881881
});
882+
883+
describe('dynamic router tabs', () => {
884+
let fixture: ComponentFixture<DynamicRouterTabsTestComponent>;
885+
let router: Router;
886+
887+
beforeEach(() => {
888+
TestBed.configureTestingModule({
889+
providers: [
890+
provideRouter([
891+
{
892+
path: '',
893+
pathMatch: 'full',
894+
redirectTo: 'one'
895+
},
896+
{
897+
path: 'one',
898+
component: DynamicRouterTabsTestComponent
899+
},
900+
{
901+
path: 'two',
902+
component: DynamicRouterTabsTestComponent
903+
},
904+
{
905+
path: 'three',
906+
component: DynamicRouterTabsTestComponent
907+
}
908+
])
909+
]
910+
});
911+
912+
router = TestBed.inject(Router);
913+
fixture = TestBed.createComponent(DynamicRouterTabsTestComponent);
914+
});
915+
916+
it('should update active tab when tabs changed', fakeAsync(() => {
917+
fixture.detectChanges();
918+
tick();
919+
fixture.detectChanges();
920+
921+
router.initialNavigation();
922+
tick();
923+
fixture.detectChanges();
924+
925+
const comp = fixture.componentInstance;
926+
927+
router.navigate(['three']);
928+
fixture.detectChanges();
929+
tick();
930+
fixture.detectChanges();
931+
932+
comp.tabs = comp.lazyTabs;
933+
fixture.detectChanges();
934+
tick();
935+
fixture.detectChanges();
936+
tick();
937+
938+
expect(comp.selectedIdx).toBe(2);
939+
flush();
940+
}));
941+
});
882942
});
883943

884944
@Component({
@@ -1139,6 +1199,42 @@ export class RouterTabsTestComponent {
11391199
handleSelection(_event: number): void {}
11401200
}
11411201

1202+
@Component({
1203+
template: `
1204+
<nz-tabset nzLinkRouter [(nzSelectedIndex)]="selectedIdx" [nzLinkExact]="false">
1205+
@for (tab of tabs; track tab.title) {
1206+
<nz-tab>
1207+
<a *nzTabLink nz-tab-link [routerLink]="tab.route">{{ tab.title }}</a>
1208+
{{ tab.title }}
1209+
</nz-tab>
1210+
}
1211+
</nz-tabset>
1212+
<router-outlet></router-outlet>
1213+
`,
1214+
imports: [RouterLink, RouterOutlet, NzTabsModule],
1215+
standalone: true
1216+
})
1217+
export class DynamicRouterTabsTestComponent {
1218+
selectedIdx = 0;
1219+
tabs = [
1220+
{
1221+
title: 'one',
1222+
route: ['one']
1223+
},
1224+
{
1225+
title: 'two',
1226+
route: ['two']
1227+
}
1228+
];
1229+
readonly lazyTabs = [
1230+
...this.tabs,
1231+
{
1232+
title: 'three',
1233+
route: ['three']
1234+
}
1235+
];
1236+
}
1237+
11421238
const routes: Routes = [
11431239
{
11441240
path: '',

components/tabs/tabset.component.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import {
5151
} from './interfaces';
5252
import { NzTabBodyComponent } from './tab-body.component';
5353
import { NzTabCloseButtonComponent } from './tab-close-button.component';
54+
import { NzTabLinkDirective } from './tab-link.directive';
5455
import { NzTabNavBarComponent } from './tab-nav-bar.component';
5556
import { NzTabNavItemDirective } from './tab-nav-item.directive';
5657
import { NZ_TAB_SET, NzTabComponent } from './tab.component';
@@ -251,6 +252,8 @@ export class NzTabSetComponent implements OnInit, AfterContentChecked, OnDestroy
251252
// We filter out only the tabs that belong to this tab set in `tabs`.
252253
@ContentChildren(NzTabComponent, { descendants: true })
253254
allTabs: QueryList<NzTabComponent> = new QueryList<NzTabComponent>();
255+
@ContentChildren(NzTabLinkDirective, { descendants: true })
256+
tabLinks: QueryList<NzTabLinkDirective> = new QueryList<NzTabLinkDirective>();
254257
@ViewChild(NzTabNavBarComponent, { static: false }) tabNavBarRef!: NzTabNavBarComponent;
255258

256259
// All the direct tabs for this tab set
@@ -475,13 +478,14 @@ export class NzTabSetComponent implements OnInit, AfterContentChecked, OnDestroy
475478
if (!this.router) {
476479
throw new Error(`${PREFIX} you should import 'RouterModule' if you want to use 'nzLinkRouter'!`);
477480
}
478-
this.router.events
479-
.pipe(
480-
takeUntil(this.destroy$),
481+
merge(
482+
this.router.events.pipe(
481483
filter(e => e instanceof NavigationEnd),
482-
startWith(true),
483484
delay(0)
484-
)
485+
),
486+
this.tabLinks.changes
487+
)
488+
.pipe(takeUntil(this.destroy$), startWith(true))
485489
.subscribe(() => {
486490
this.updateRouterActive();
487491
this.cdr.markForCheck();
@@ -495,7 +499,7 @@ export class NzTabSetComponent implements OnInit, AfterContentChecked, OnDestroy
495499
if (index !== this.selectedIndex) {
496500
this.setSelectedIndex(index);
497501
}
498-
this.nzHideAll = index === -1;
502+
Promise.resolve().then(() => (this.nzHideAll = index === -1));
499503
}
500504
}
501505

0 commit comments

Comments
 (0)