Skip to content

Commit a2906dd

Browse files
authored
fix(material/tabs): attach content inside the zone (#31868)
The tabs run their animation events outside the zone which means that attaching the content as a result will be outside the zone as well. These changes bring it back into the zone to ensure that things like error handling work correctly. Fixes #31867.
1 parent 31562a4 commit a2906dd

File tree

1 file changed

+11
-3
lines changed

1 file changed

+11
-3
lines changed

src/material/tabs/tab-body.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {_animationsDisabled} from '../core';
3939
@Directive({selector: '[matTabBodyHost]'})
4040
export class MatTabBodyPortal extends CdkPortalOutlet implements OnInit, OnDestroy {
4141
private _host = inject(MatTabBody);
42+
private _ngZone = inject(NgZone);
4243

4344
/** Subscription to events for when the tab body begins centering. */
4445
private _centeringSub = Subscription.EMPTY;
@@ -59,13 +60,20 @@ export class MatTabBodyPortal extends CdkPortalOutlet implements OnInit, OnDestr
5960
.pipe(startWith(this._host._isCenterPosition()))
6061
.subscribe((isCentering: boolean) => {
6162
if (this._host._content && isCentering && !this.hasAttached()) {
62-
this.attach(this._host._content);
63+
// Attach in the zone since the events from the tab body may be happening outside.
64+
// See: https://github.com/angular/components/issues/31867
65+
this._ngZone.run(() => {
66+
// `Promise.resolve` is necessary to destabilize the zone.
67+
// Otherwise some apps throw a `ApplicationRef.tick is called recursively` error.
68+
Promise.resolve().then();
69+
this.attach(this._host._content);
70+
});
6371
}
6472
});
6573

6674
this._leavingSub = this._host._afterLeavingCenter.subscribe(() => {
6775
if (!this._host.preserveContent) {
68-
this.detach();
76+
this._ngZone.run(() => this.detach());
6977
}
7078
});
7179
}
@@ -117,7 +125,7 @@ export type MatTabBodyOriginState = 'left' | 'right';
117125
changeDetection: ChangeDetectionStrategy.Default,
118126
host: {
119127
'class': 'mat-mdc-tab-body',
120-
// In most cases the `visibility: hidden` that we set on the off-screen content is enough
128+
// In most cases the `hidden` that we set on the off-screen content is enough
121129
// to stop interactions with it, but if a child element sets its own `visibility`, it'll
122130
// override the one from the parent. This ensures that even those elements will be removed
123131
// from the accessibility tree.

0 commit comments

Comments
 (0)