@@ -36,9 +36,10 @@ import {
3636 mixinDisableRipple ,
3737 ThemePalette ,
3838} from '@angular/material/core' ;
39- import { merge , Subscription } from 'rxjs' ;
40- import { MatTab } from './tab' ;
4139import { ANIMATION_MODULE_TYPE } from '@angular/platform-browser/animations' ;
40+ import { merge , Subscription } from 'rxjs' ;
41+ import { startWith } from 'rxjs/operators' ;
42+ import { MatTab , MAT_TAB_GROUP } from './tab' ;
4243
4344
4445/** Used to generate unique ID's for each tab component */
@@ -88,10 +89,18 @@ interface MatTabGroupBaseHeader {
8889// tslint:disable-next-line:class-name
8990export abstract class _MatTabGroupBase extends _MatTabGroupMixinBase implements AfterContentInit ,
9091 AfterContentChecked , OnDestroy , CanColor , CanDisableRipple {
91- abstract _tabs : QueryList < MatTab > ;
92+
93+ /**
94+ * All tabs inside the tab group. This includes tabs that belong to groups that are nested
95+ * inside the current one. We filter out only the tabs that belong to this group in `_tabs`.
96+ */
97+ abstract _allTabs : QueryList < MatTab > ;
9298 abstract _tabBodyWrapper : ElementRef ;
9399 abstract _tabHeader : MatTabGroupBaseHeader ;
94100
101+ /** All of the tabs that belong to the group. */
102+ _tabs : QueryList < MatTab > = new QueryList < MatTab > ( ) ;
103+
95104 /** The tab index that should be selected after the content has been checked. */
96105 private _indexToSelect : number | null = 0 ;
97106
@@ -220,6 +229,7 @@ export abstract class _MatTabGroupBase extends _MatTabGroupMixinBase implements
220229 }
221230
222231 ngAfterContentInit ( ) {
232+ this . _subscribeToAllTabChanges ( ) ;
223233 this . _subscribeToTabLabels ( ) ;
224234
225235 // Subscribe to changes in the amount of tabs, in order to be
@@ -243,11 +253,27 @@ export abstract class _MatTabGroupBase extends _MatTabGroupMixinBase implements
243253 }
244254 }
245255
246- this . _subscribeToTabLabels ( ) ;
247256 this . _changeDetectorRef . markForCheck ( ) ;
248257 } ) ;
249258 }
250259
260+ /** Listens to changes in all of the tabs. */
261+ private _subscribeToAllTabChanges ( ) {
262+ // Since we use a query with `descendants: true` to pick up the tabs, we may end up catching
263+ // some that are inside of nested tab groups. We filter them out manually by checking that
264+ // the closest group to the tab is the current one.
265+ this . _allTabs . changes
266+ . pipe ( startWith ( this . _allTabs ) )
267+ . subscribe ( ( tabs : QueryList < MatTab > ) => {
268+ this . _tabs . reset ( tabs . filter ( tab => {
269+ // @breaking -change 10.0.0 Remove null check for `_closestTabGroup`
270+ // once it becomes a required parameter in MatTab.
271+ return ! tab . _closestTabGroup || tab . _closestTabGroup === this ;
272+ } ) ) ;
273+ this . _tabs . notifyOnChanges ( ) ;
274+ } ) ;
275+ }
276+
251277 ngOnDestroy ( ) {
252278 this . _tabsSubscription . unsubscribe ( ) ;
253279 this . _tabLabelSubscription . unsubscribe ( ) ;
@@ -363,14 +389,18 @@ export abstract class _MatTabGroupBase extends _MatTabGroupMixinBase implements
363389 // tslint:disable-next-line:validate-decorators
364390 changeDetection : ChangeDetectionStrategy . Default ,
365391 inputs : [ 'color' , 'disableRipple' ] ,
392+ providers : [ {
393+ provide : MAT_TAB_GROUP ,
394+ useExisting : MatTabGroup
395+ } ] ,
366396 host : {
367397 'class' : 'mat-tab-group' ,
368398 '[class.mat-tab-group-dynamic-height]' : 'dynamicHeight' ,
369399 '[class.mat-tab-group-inverted-header]' : 'headerPosition === "below"' ,
370400 } ,
371401} )
372402export class MatTabGroup extends _MatTabGroupBase {
373- @ContentChildren ( MatTab ) _tabs : QueryList < MatTab > ;
403+ @ContentChildren ( MatTab , { descendants : true } ) _allTabs : QueryList < MatTab > ;
374404 @ViewChild ( 'tabBodyWrapper' , { static : false } ) _tabBodyWrapper : ElementRef ;
375405 @ViewChild ( 'tabHeader' , { static : false } ) _tabHeader : MatTabGroupBaseHeader ;
376406
0 commit comments