Skip to content

Commit 3e54a92

Browse files
committed
fix(tabs): maintain selected tab when new tabs are added or removed
Maintains the `selectedIndex` of the current tab when a new tab is added or removed. Previously, changing the amount of tabs would shift the array, causing a different tab to be selected. Fixes #7738.
1 parent b67813e commit 3e54a92

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed

src/lib/tabs/tab-group.spec.ts

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,14 +282,17 @@ describe('MatTabGroup', () => {
282282
expect(tabs[3].origin).toBeGreaterThanOrEqual(0);
283283

284284
// Add a new tab in the beginning and select it, expect an origin < than 0 (animate left)
285-
fixture.componentInstance.tabs.push({label: 'New tab', content: 'to left of index'});
286285
fixture.componentInstance.selectedIndex = 0;
287286
fixture.detectChanges();
288287
tick();
289288

289+
fixture.componentInstance.tabs.push({label: 'New tab', content: 'to left of index'});
290+
fixture.detectChanges();
291+
tick();
292+
290293
tabs = component._tabs.toArray();
291294
expect(tabs[0].origin).toBeLessThan(0);
292-
}));
295+
}));
293296

294297

295298
it('should update selected index if the last tab removed while selected', fakeAsync(() => {
@@ -309,6 +312,47 @@ describe('MatTabGroup', () => {
309312
expect(component.selectedIndex).toBe(numberOfTabs - 2);
310313
}));
311314

315+
316+
it('should maintain the selected tab if a new tab is added', () => {
317+
fixture.detectChanges();
318+
const component: MatTabGroup =
319+
fixture.debugElement.query(By.css('mat-tab-group')).componentInstance;
320+
321+
fixture.componentInstance.selectedIndex = 1;
322+
fixture.detectChanges();
323+
324+
// Add a new tab at the beginning.
325+
fixture.componentInstance.tabs.unshift({label: 'New tab', content: 'at the start'});
326+
fixture.detectChanges();
327+
328+
expect(component.selectedIndex).toBe(2);
329+
expect(component._tabs.toArray()[2].isActive).toBe(true);
330+
});
331+
332+
333+
it('should maintain the selected tab if a tab is removed', () => {
334+
// Add a couple of tabs so we have more to work with.
335+
fixture.componentInstance.tabs.push(
336+
{label: 'New tab', content: 'with new content'},
337+
{label: 'Another new tab', content: 'with newer content'}
338+
);
339+
340+
// Select the second-to-last tab.
341+
fixture.componentInstance.selectedIndex = 3;
342+
fixture.detectChanges();
343+
344+
const component: MatTabGroup =
345+
fixture.debugElement.query(By.css('mat-tab-group')).componentInstance;
346+
347+
// Remove a tab right before the selected one.
348+
fixture.componentInstance.tabs.splice(2, 1);
349+
fixture.detectChanges();
350+
351+
expect(component.selectedIndex).toBe(1);
352+
expect(component._tabs.toArray()[1].isActive).toBe(true);
353+
});
354+
355+
312356
});
313357

314358
describe('async tabs', () => {

src/lib/tabs/tab-group.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,16 @@ export class MatTabGroup extends _MatTabGroupMixinBase implements AfterContentIn
200200
// Subscribe to changes in the amount of tabs, in order to be
201201
// able to re-render the content as new tabs are added or removed.
202202
this._tabsSubscription = this._tabs.changes.subscribe(() => {
203+
const tabs = this._tabs.toArray();
204+
205+
// Maintain the previously-selected tab if a new tab is added or removed.
206+
for (let i = 0; i < tabs.length; i++) {
207+
if (tabs[i].isActive) {
208+
this._indexToSelect = i;
209+
break;
210+
}
211+
}
212+
203213
this._subscribeToTabLabels();
204214
this._changeDetectorRef.markForCheck();
205215
});

0 commit comments

Comments
 (0)