From 78f556a37b6b5f154e20929afd15b796e916d135 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 29 Jun 2018 20:11:21 +0200 Subject: [PATCH] fix(tabs): maintain selected tab when new tabs are added or removed (#9132) --- src/lib/tabs/tab-group.spec.ts | 48 ++++++++++++++++++++++++++++++++-- src/lib/tabs/tab-group.ts | 10 +++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/lib/tabs/tab-group.spec.ts b/src/lib/tabs/tab-group.spec.ts index 89e0392a1e2..77d762455b4 100644 --- a/src/lib/tabs/tab-group.spec.ts +++ b/src/lib/tabs/tab-group.spec.ts @@ -333,14 +333,17 @@ describe('MatTabGroup', () => { expect(tabs[3].origin).toBeGreaterThanOrEqual(0); // Add a new tab in the beginning and select it, expect an origin < than 0 (animate left) - fixture.componentInstance.tabs.push({label: 'New tab', content: 'to left of index'}); fixture.componentInstance.selectedIndex = 0; fixture.detectChanges(); tick(); + fixture.componentInstance.tabs.push({label: 'New tab', content: 'to left of index'}); + fixture.detectChanges(); + tick(); + tabs = component._tabs.toArray(); expect(tabs[0].origin).toBeLessThan(0); - })); + })); it('should update selected index if the last tab removed while selected', fakeAsync(() => { @@ -360,6 +363,47 @@ describe('MatTabGroup', () => { expect(component.selectedIndex).toBe(numberOfTabs - 2); })); + + it('should maintain the selected tab if a new tab is added', () => { + fixture.detectChanges(); + const component: MatTabGroup = + fixture.debugElement.query(By.css('mat-tab-group')).componentInstance; + + fixture.componentInstance.selectedIndex = 1; + fixture.detectChanges(); + + // Add a new tab at the beginning. + fixture.componentInstance.tabs.unshift({label: 'New tab', content: 'at the start'}); + fixture.detectChanges(); + + expect(component.selectedIndex).toBe(2); + expect(component._tabs.toArray()[2].isActive).toBe(true); + }); + + + it('should maintain the selected tab if a tab is removed', () => { + // Add a couple of tabs so we have more to work with. + fixture.componentInstance.tabs.push( + {label: 'New tab', content: 'with new content'}, + {label: 'Another new tab', content: 'with newer content'} + ); + + // Select the second-to-last tab. + fixture.componentInstance.selectedIndex = 3; + fixture.detectChanges(); + + const component: MatTabGroup = + fixture.debugElement.query(By.css('mat-tab-group')).componentInstance; + + // Remove a tab right before the selected one. + fixture.componentInstance.tabs.splice(2, 1); + fixture.detectChanges(); + + expect(component.selectedIndex).toBe(1); + expect(component._tabs.toArray()[1].isActive).toBe(true); + }); + + }); describe('async tabs', () => { diff --git a/src/lib/tabs/tab-group.ts b/src/lib/tabs/tab-group.ts index 5e9c4749fb7..5d45471f1ee 100644 --- a/src/lib/tabs/tab-group.ts +++ b/src/lib/tabs/tab-group.ts @@ -200,6 +200,16 @@ export class MatTabGroup extends _MatTabGroupMixinBase implements AfterContentIn // Subscribe to changes in the amount of tabs, in order to be // able to re-render the content as new tabs are added or removed. this._tabsSubscription = this._tabs.changes.subscribe(() => { + const tabs = this._tabs.toArray(); + + // Maintain the previously-selected tab if a new tab is added or removed. + for (let i = 0; i < tabs.length; i++) { + if (tabs[i].isActive) { + this._indexToSelect = i; + break; + } + } + this._subscribeToTabLabels(); this._changeDetectorRef.markForCheck(); });