Skip to content

Commit 1d9f401

Browse files
committed
feat(tabs/bottomnav): routing support #4297
1 parent 6949521 commit 1d9f401

File tree

3 files changed

+116
-6
lines changed

3 files changed

+116
-6
lines changed

projects/igniteui-angular/src/lib/tabbar/tabbar.component.ts

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ import {
2222
} from '@angular/core';
2323
import { IgxBadgeModule } from '../badge/badge.component';
2424
import { IgxIconModule } from '../icon/index';
25+
import { NavigationEnd, Router, RouterLink } from '@angular/router';
26+
import { Subscription } from 'rxjs';
27+
import { filter } from 'rxjs/operators';
2528

2629
export interface ISelectTabEventArgs {
2730
tab: IgxTabComponent;
@@ -38,6 +41,7 @@ export class IgxTabTemplateDirective {
3841
constructor(public template: TemplateRef<any>) {
3942
}
4043
}
44+
4145
/**
4246
* **Ignite UI for Angular Tab Bar** -
4347
* [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tabbar.html)
@@ -63,6 +67,7 @@ export class IgxTabTemplateDirective {
6367
`]
6468
})
6569
export class IgxBottomNavComponent implements AfterViewInit {
70+
6671
/**
6772
* Gets the `IgxTabComponent` elements in the tab bar component.
6873
* ```typescript
@@ -71,6 +76,7 @@ export class IgxBottomNavComponent implements AfterViewInit {
7176
* @memberof IgxBottomNavComponent
7277
*/
7378
@ViewChildren(forwardRef(() => IgxTabComponent)) public tabs: QueryList<IgxTabComponent>;
79+
7480
/**
7581
* Gets the `IgxTabPanelComponent` elements in the tab bar component.
7682
* ```typescript
@@ -94,6 +100,7 @@ export class IgxBottomNavComponent implements AfterViewInit {
94100
@HostBinding('attr.id')
95101
@Input()
96102
public id = `igx-bottom-nav-${NEXT_ID++}`;
103+
97104
/**
98105
* Emits an event when a new tab is selected.
99106
* Provides references to the `IgxTabComponent` and `IgxTabPanelComponent` as event arguments.
@@ -103,6 +110,7 @@ export class IgxBottomNavComponent implements AfterViewInit {
103110
* @memberof IgxBottomNavComponent
104111
*/
105112
@Output() public onTabSelected = new EventEmitter<ISelectTabEventArgs>();
113+
106114
/**
107115
* Emits an event when a tab is deselected.
108116
* Provides references to the `IgxTabComponent` and `IgxTabPanelComponent` as event arguments.
@@ -112,6 +120,7 @@ export class IgxBottomNavComponent implements AfterViewInit {
112120
* @memberof IgxBottomNavComponent
113121
*/
114122
@Output() public onTabDeselected = new EventEmitter<ISelectTabEventArgs>();
123+
115124
/**
116125
* Gets the `index` of selected tab/panel in the respective collection.
117126
* ```typescript
@@ -120,6 +129,7 @@ export class IgxBottomNavComponent implements AfterViewInit {
120129
* @memberof IgxBottomNavComponent
121130
*/
122131
public selectedIndex = -1;
132+
123133
/**
124134
* Gets the `itemStyle` of the tab bar.
125135
* ```typescript
@@ -130,10 +140,12 @@ export class IgxBottomNavComponent implements AfterViewInit {
130140
public get itemStyle(): string {
131141
return this._itemStyle;
132142
}
143+
133144
/**
134145
*@hidden
135146
*/
136147
private _itemStyle = 'igx-bottom-nav';
148+
137149
/**
138150
* Gets the selected tab in the tab bar.
139151
* ```typescript
@@ -147,13 +159,33 @@ export class IgxBottomNavComponent implements AfterViewInit {
147159
}
148160
}
149161

150-
constructor(private _element: ElementRef) {
162+
/**
163+
* @hidden
164+
*/
165+
private _navigationEndSubscription: Subscription;
166+
167+
constructor(private _element: ElementRef, private router: Router) {
151168
}
169+
152170
/**
153171
*@hidden
154172
*/
155173
public ngAfterViewInit() {
156174
// initial selection
175+
this._navigationEndSubscription = this.router.events.pipe(
176+
filter(event => event instanceof NavigationEnd)).subscribe((args) => {
177+
const panelsArray = this.panels.toArray();
178+
for (let i = 0; i < panelsArray.length; i++) {
179+
if (panelsArray[i].routerLinkDirective &&
180+
this.router.url.startsWith(panelsArray[i].routerLinkDirective.urlTree.toString())) {
181+
panelsArray[i].selectAndUpdateRoute(false);
182+
break;
183+
}
184+
}
185+
this._navigationEndSubscription.unsubscribe();
186+
}
187+
);
188+
157189
setTimeout(() => {
158190
if (this.selectedIndex === -1) {
159191
const selectablePanels = this.panels.filter((p) => !p.disabled);
@@ -165,6 +197,7 @@ export class IgxBottomNavComponent implements AfterViewInit {
165197
}
166198
}, 0);
167199
}
200+
168201
/**
169202
*@hidden
170203
*/
@@ -178,6 +211,7 @@ export class IgxBottomNavComponent implements AfterViewInit {
178211
}
179212
});
180213
}
214+
181215
/**
182216
*@hidden
183217
*/
@@ -204,6 +238,7 @@ export class IgxTabPanelComponent implements AfterContentInit, AfterViewChecked
204238
*@hidden
205239
*/
206240
private _itemStyle = 'igx-tab-panel';
241+
207242
/**
208243
* Sets/gets the `label` of the tab panel.
209244
* ```html
@@ -215,6 +250,7 @@ export class IgxTabPanelComponent implements AfterContentInit, AfterViewChecked
215250
* @memberof IgxTabPanelComponent
216251
*/
217252
@Input() public label: string;
253+
218254
/**
219255
* Sets/gets the `icon` of the tab panel.
220256
* ```html
@@ -226,6 +262,7 @@ export class IgxTabPanelComponent implements AfterContentInit, AfterViewChecked
226262
* @memberof IgxTabPanelComponent
227263
*/
228264
@Input() public icon: string;
265+
229266
/**
230267
* Sets/gets whether the tab panel is disabled.
231268
* ```html
@@ -237,6 +274,7 @@ export class IgxTabPanelComponent implements AfterContentInit, AfterViewChecked
237274
* @memberof IgxTabPanelComponent
238275
*/
239276
@Input() public disabled: boolean;
277+
240278
/**
241279
* Gets the role of the tab panel.
242280
* ```typescript
@@ -245,6 +283,7 @@ export class IgxTabPanelComponent implements AfterContentInit, AfterViewChecked
245283
* @memberof IgxTabPanelComponent
246284
*/
247285
@HostBinding('attr.role') public role = 'tabpanel';
286+
248287
/**
249288
* Gets whether a tab panel will have `igx-bottom-nav__panel` class.
250289
* ```typescript
@@ -256,6 +295,7 @@ export class IgxTabPanelComponent implements AfterContentInit, AfterViewChecked
256295
get styleClass(): boolean {
257296
return (!this.isSelected);
258297
}
298+
259299
/**
260300
* Sets/gets whether a tab panel is selected.
261301
* ```typescript
@@ -268,6 +308,7 @@ export class IgxTabPanelComponent implements AfterContentInit, AfterViewChecked
268308
*/
269309
@HostBinding('class.igx-bottom-nav__panel--selected')
270310
public isSelected = false;
311+
271312
/**
272313
* Gets the `itemStyle` of the tab panel.
273314
* ```typescript
@@ -278,6 +319,7 @@ export class IgxTabPanelComponent implements AfterContentInit, AfterViewChecked
278319
public get itemStyle(): string {
279320
return this._itemStyle;
280321
}
322+
281323
/**
282324
* Gets the tab associated with the panel.
283325
* ```typescript
@@ -290,6 +332,7 @@ export class IgxTabPanelComponent implements AfterContentInit, AfterViewChecked
290332
return this._tabBar.tabs.toArray()[this.index];
291333
}
292334
}
335+
293336
/**
294337
* Gets the index of a panel in the panels collection.
295338
* ```typescript
@@ -302,6 +345,7 @@ export class IgxTabPanelComponent implements AfterContentInit, AfterViewChecked
302345
return this._tabBar.panels.toArray().indexOf(this);
303346
}
304347
}
348+
305349
/**
306350
* Gets the tab template.
307351
* ```typescript
@@ -312,6 +356,7 @@ export class IgxTabPanelComponent implements AfterContentInit, AfterViewChecked
312356
get customTabTemplate(): TemplateRef<any> {
313357
return this._tabTemplate;
314358
}
359+
315360
/**
316361
* Sets the tab template.
317362
* ```typescript
@@ -322,18 +367,27 @@ export class IgxTabPanelComponent implements AfterContentInit, AfterViewChecked
322367
set customTabTemplate(template: TemplateRef<any>) {
323368
this._tabTemplate = template;
324369
}
370+
325371
/**
326372
*@hidden
327373
*/
328374
private _tabTemplate: TemplateRef<any>;
375+
329376
/**
330377
*@hidden
331378
*/
332379
@ContentChild(IgxTabTemplateDirective, { read: IgxTabTemplateDirective })
333380
protected tabTemplate: IgxTabTemplateDirective;
334381

382+
/**
383+
*@hidden
384+
*/
385+
@ContentChild(RouterLink)
386+
public routerLinkDirective: RouterLink;
387+
335388
constructor(private _tabBar: IgxBottomNavComponent, private _element: ElementRef) {
336389
}
390+
337391
/**
338392
*@hidden
339393
*/
@@ -342,13 +396,15 @@ export class IgxTabPanelComponent implements AfterContentInit, AfterViewChecked
342396
this._tabTemplate = this.tabTemplate.template;
343397
}
344398
}
399+
345400
/**
346401
*@hidden
347402
*/
348403
public ngAfterViewChecked() {
349404
this._element.nativeElement.setAttribute('aria-labelledby', `igx-tab-${this.index}`);
350405
this._element.nativeElement.setAttribute('id', `igx-bottom-nav__panel-${this.index}`);
351406
}
407+
352408
/**
353409
* Selects the current tab and the tab panel.
354410
* ```typescript
@@ -357,11 +413,20 @@ export class IgxTabPanelComponent implements AfterContentInit, AfterViewChecked
357413
* @memberof IgxTabPanelComponent
358414
*/
359415
public select() {
416+
this.selectAndUpdateRoute(true);
417+
}
418+
419+
/**
420+
*@hidden
421+
*/
422+
public selectAndUpdateRoute(updateRoute: boolean) {
360423
if (this.disabled || this._tabBar.selectedIndex === this.index) {
361424
return;
362425
}
363-
364426
this.isSelected = true;
427+
if (updateRoute && this.routerLinkDirective) {
428+
this.routerLinkDirective.onClick();
429+
}
365430
this._tabBar.onTabSelected.emit({ tab: this._tabBar.tabs.toArray()[this.index], panel: this });
366431
}
367432
}
@@ -374,6 +439,7 @@ export class IgxTabPanelComponent implements AfterContentInit, AfterViewChecked
374439
})
375440

376441
export class IgxTabComponent {
442+
377443
/**
378444
* Gets the `role` attribute.
379445
* ```typescript
@@ -382,6 +448,7 @@ export class IgxTabComponent {
382448
* @memberof IgxTabComponent
383449
*/
384450
@HostBinding('attr.role') public role = 'tab';
451+
385452
/**
386453
* Gets the panel associated with the tab.
387454
* ```typescript
@@ -390,10 +457,12 @@ export class IgxTabComponent {
390457
* @memberof IgxTabComponent
391458
*/
392459
@Input() public relatedPanel: IgxTabPanelComponent;
460+
393461
/**
394462
*@hidden
395463
*/
396464
private _changesCount = 0; // changes and updates accordingly applied to the tab.
465+
397466
/**
398467
* Gets the changes and updates accordingly applied to the tab.
399468
*
@@ -402,6 +471,7 @@ export class IgxTabComponent {
402471
get changesCount(): number {
403472
return this._changesCount;
404473
}
474+
405475
/**
406476
* Gets whether the tab is disabled.
407477
* ```typescript
@@ -416,6 +486,7 @@ export class IgxTabComponent {
416486
return panel.disabled;
417487
}
418488
}
489+
419490
/**
420491
* Gets whether the tab is selected.
421492
* ```typescript
@@ -430,6 +501,7 @@ export class IgxTabComponent {
430501
return panel.isSelected;
431502
}
432503
}
504+
433505
/**
434506
* Gets the `index` of the tab.
435507
* ```typescript
@@ -443,6 +515,7 @@ export class IgxTabComponent {
443515

444516
constructor(private _tabBar: IgxBottomNavComponent, private _element: ElementRef) {
445517
}
518+
446519
/**
447520
* Selects the current tab and the associated panel.
448521
* ```typescript

projects/igniteui-angular/src/lib/tabs/tabs-group.component.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
import { IgxTabItemComponent } from './tab-item.component';
1414
import { IgxTabItemTemplateDirective } from './tabs.directives';
1515
import { IgxTabsBase, IgxTabsGroupBase } from './tabs.common';
16+
import { RouterLink } from '@angular/router';
1617

1718
@Component({
1819
selector: 'igx-tabs-group',
@@ -59,6 +60,12 @@ export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit
5960

6061
private _tabTemplate: TemplateRef<any>;
6162

63+
/**
64+
* @hidden
65+
*/
66+
@ContentChild(RouterLink)
67+
public routerLinkDirective: RouterLink;
68+
6269
constructor(private _tabs: IgxTabsBase, private _element: ElementRef) {
6370
}
6471

@@ -160,7 +167,7 @@ export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit
160167
*```
161168
* @param focusDelay A number representing the expected delay.
162169
*/
163-
public select(focusDelay = 200): void {
170+
public select(focusDelay = 200, updateRoute: boolean = true): void {
164171
if (this.disabled || this.isSelected) {
165172
return;
166173
}
@@ -174,6 +181,10 @@ export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit
174181
}, focusDelay);
175182
}
176183
this.handleSelection();
184+
if (updateRoute && this.routerLinkDirective) {
185+
console.log('@@ tabs-group: navigating to ' + this.routerLinkDirective.urlTree.toString());
186+
this.routerLinkDirective.onClick();
187+
}
177188
this._tabs.onTabItemSelected.emit({ tab: this._tabs.tabs.toArray()[this.index], group: this });
178189
}
179190

0 commit comments

Comments
 (0)