Skip to content

Commit 7f274dc

Browse files
crisbetoandrewseguin
authored andcommitted
fix(material/snack-bar): ensure that the snack bar always runs inside the NgZone (#24611)
Adds an extra call to ensure that the snack bar is inside the NgZone. This is something that has come up several times in internal tests where some API call is stubbed out, pulling the snack bar outside the zone and causing tests to fail when we remove a change detection somewhere. **Note:** I had a hard time reproducing this in our own tests, presumably because the fixture ends up pulling it back into the zone. (cherry picked from commit 99f1f38)
1 parent 651de3c commit 7f274dc

File tree

2 files changed

+35
-23
lines changed

2 files changed

+35
-23
lines changed

src/material-experimental/mdc-snack-bar/snack-bar-container.ts

+14-8
Original file line numberDiff line numberDiff line change
@@ -176,18 +176,24 @@ export class MatSnackBarContainer
176176
enter() {
177177
// MDC uses some browser APIs that will throw during server-side rendering.
178178
if (this._platform.isBrowser) {
179-
this._mdcFoundation.open();
180-
this._screenReaderAnnounce();
179+
this._ngZone.run(() => {
180+
this._mdcFoundation.open();
181+
this._screenReaderAnnounce();
182+
});
181183
}
182184
}
183185

184186
exit(): Observable<void> {
185-
this._exiting = true;
186-
this._mdcFoundation.close();
187-
188-
// If the snack bar hasn't been announced by the time it exits it wouldn't have been open
189-
// long enough to visually read it either, so clear the timeout for announcing.
190-
clearTimeout(this._announceTimeoutId);
187+
// It's common for snack bars to be opened by random outside calls like HTTP requests or
188+
// errors. Run inside the NgZone to ensure that it functions correctly.
189+
this._ngZone.run(() => {
190+
this._exiting = true;
191+
this._mdcFoundation.close();
192+
193+
// If the snack bar hasn't been announced by the time it exits it wouldn't have been open
194+
// long enough to visually read it either, so clear the timeout for announcing.
195+
clearTimeout(this._announceTimeoutId);
196+
});
191197

192198
return this._onExit;
193199
}

src/material/snack-bar/snack-bar-container.ts

+21-15
Original file line numberDiff line numberDiff line change
@@ -194,19 +194,23 @@ export class MatSnackBarContainer
194194

195195
/** Begin animation of the snack bar exiting from view. */
196196
exit(): Observable<void> {
197-
// Note: this one transitions to `hidden`, rather than `void`, in order to handle the case
198-
// where multiple snack bars are opened in quick succession (e.g. two consecutive calls to
199-
// `MatSnackBar.open`).
200-
this._animationState = 'hidden';
201-
202-
// Mark this element with an 'exit' attribute to indicate that the snackbar has
203-
// been dismissed and will soon be removed from the DOM. This is used by the snackbar
204-
// test harness.
205-
this._elementRef.nativeElement.setAttribute('mat-exit', '');
206-
207-
// If the snack bar hasn't been announced by the time it exits it wouldn't have been open
208-
// long enough to visually read it either, so clear the timeout for announcing.
209-
clearTimeout(this._announceTimeoutId);
197+
// It's common for snack bars to be opened by random outside calls like HTTP requests or
198+
// errors. Run inside the NgZone to ensure that it functions correctly.
199+
this._ngZone.run(() => {
200+
// Note: this one transitions to `hidden`, rather than `void`, in order to handle the case
201+
// where multiple snack bars are opened in quick succession (e.g. two consecutive calls to
202+
// `MatSnackBar.open`).
203+
this._animationState = 'hidden';
204+
205+
// Mark this element with an 'exit' attribute to indicate that the snackbar has
206+
// been dismissed and will soon be removed from the DOM. This is used by the snackbar
207+
// test harness.
208+
this._elementRef.nativeElement.setAttribute('mat-exit', '');
209+
210+
// If the snack bar hasn't been announced by the time it exits it wouldn't have been open
211+
// long enough to visually read it either, so clear the timeout for announcing.
212+
clearTimeout(this._announceTimeoutId);
213+
});
210214

211215
return this._onExit;
212216
}
@@ -223,8 +227,10 @@ export class MatSnackBarContainer
223227
*/
224228
private _completeExit() {
225229
this._ngZone.onMicrotaskEmpty.pipe(take(1)).subscribe(() => {
226-
this._onExit.next();
227-
this._onExit.complete();
230+
this._ngZone.run(() => {
231+
this._onExit.next();
232+
this._onExit.complete();
233+
});
228234
});
229235
}
230236

0 commit comments

Comments
 (0)