7
7
*/
8
8
9
9
import {
10
+ ANIMATION_MODULE_TYPE ,
10
11
ChangeDetectionStrategy ,
11
- ChangeDetectorRef ,
12
12
Component ,
13
13
ComponentRef ,
14
14
ElementRef ,
@@ -20,7 +20,6 @@ import {
20
20
ViewEncapsulation ,
21
21
} from '@angular/core' ;
22
22
import { DOCUMENT } from '@angular/common' ;
23
- import { matSnackBarAnimations } from './snack-bar-animations' ;
24
23
import {
25
24
BasePortalOutlet ,
26
25
CdkPortalOutlet ,
@@ -31,7 +30,6 @@ import {
31
30
import { Observable , Subject } from 'rxjs' ;
32
31
import { _IdGenerator , AriaLivePoliteness } from '@angular/cdk/a11y' ;
33
32
import { Platform } from '@angular/cdk/platform' ;
34
- import { AnimationEvent } from '@angular/animations' ;
35
33
import { MatSnackBarConfig } from './snack-bar-config' ;
36
34
37
35
/**
@@ -48,19 +46,21 @@ import {MatSnackBarConfig} from './snack-bar-config';
48
46
// tslint:disable-next-line:validate-decorators
49
47
changeDetection : ChangeDetectionStrategy . Default ,
50
48
encapsulation : ViewEncapsulation . None ,
51
- animations : [ matSnackBarAnimations . snackBarState ] ,
52
49
imports : [ CdkPortalOutlet ] ,
53
50
host : {
54
51
'class' : 'mdc-snackbar mat-mdc-snack-bar-container' ,
55
- '[@state ]' : '_animationState ' ,
56
- '(@state.done )' : 'onAnimationEnd ($event)' ,
52
+ '[class.mat-snack-bar-animations-enabled ]' : '!_animationsDisabled ' ,
53
+ '(animationend )' : '_animationDone ($event)' ,
57
54
} ,
58
55
} )
59
56
export class MatSnackBarContainer extends BasePortalOutlet implements OnDestroy {
60
57
private _ngZone = inject ( NgZone ) ;
61
58
private _elementRef = inject < ElementRef < HTMLElement > > ( ElementRef ) ;
62
- private _changeDetectorRef = inject ( ChangeDetectorRef ) ;
63
59
private _platform = inject ( Platform ) ;
60
+ private _enterFallback : ReturnType < typeof setTimeout > | undefined ;
61
+ private _exitFallback : ReturnType < typeof setTimeout > | undefined ;
62
+ protected _animationsDisabled =
63
+ inject ( ANIMATION_MODULE_TYPE , { optional : true } ) === 'NoopAnimations' ;
64
64
snackBarConfig = inject ( MatSnackBarConfig ) ;
65
65
66
66
private _document = inject ( DOCUMENT ) ;
@@ -70,7 +70,7 @@ export class MatSnackBarContainer extends BasePortalOutlet implements OnDestroy
70
70
private readonly _announceDelay : number = 150 ;
71
71
72
72
/** The timeout for announcing the snack bar's content. */
73
- private _announceTimeoutId : ReturnType < typeof setTimeout > ;
73
+ private _announceTimeoutId : ReturnType < typeof setTimeout > | undefined ;
74
74
75
75
/** Whether the component has been destroyed. */
76
76
private _destroyed = false ;
@@ -87,9 +87,6 @@ export class MatSnackBarContainer extends BasePortalOutlet implements OnDestroy
87
87
/** Subject for notifying that the snack bar has finished entering the view. */
88
88
readonly _onEnter : Subject < void > = new Subject ( ) ;
89
89
90
- /** The state of the snack bar animations. */
91
- _animationState = 'void' ;
92
-
93
90
/** aria-live value for the live region. */
94
91
_live : AriaLivePoliteness ;
95
92
@@ -166,78 +163,82 @@ export class MatSnackBarContainer extends BasePortalOutlet implements OnDestroy
166
163
} ;
167
164
168
165
/** Handle end of animations, updating the state of the snackbar. */
169
- onAnimationEnd ( event : AnimationEvent ) {
170
- const { fromState , toState } = event ;
171
-
172
- if ( ( toState === 'void' && fromState !== 'void' ) || toState === 'hidden ') {
166
+ protected _animationDone ( event : AnimationEvent ) {
167
+ if ( event . animationName === '_mat-snack-bar-enter' ) {
168
+ this . _completeEnter ( ) ;
169
+ } else if ( event . animationName === '_mat-snack-bar-exit ' ) {
173
170
this . _completeExit ( ) ;
174
171
}
175
-
176
- if ( toState === 'visible' ) {
177
- // Note: we shouldn't use `this` inside the zone callback,
178
- // because it can cause a memory leak.
179
- const onEnter = this . _onEnter ;
180
-
181
- this . _ngZone . run ( ( ) => {
182
- onEnter . next ( ) ;
183
- onEnter . complete ( ) ;
184
- } ) ;
185
- }
186
172
}
187
173
188
174
/** Begin animation of snack bar entrance into view. */
189
175
enter ( ) : void {
190
176
if ( ! this . _destroyed ) {
191
- this . _animationState = 'visible' ;
192
- // _animationState lives in host bindings and `detectChanges` does not refresh host bindings
193
- // so we have to call `markForCheck` to ensure the host view is refreshed eventually.
194
- this . _changeDetectorRef . markForCheck ( ) ;
195
- this . _changeDetectorRef . detectChanges ( ) ;
196
177
this . _screenReaderAnnounce ( ) ;
178
+
179
+ if ( this . _animationsDisabled ) {
180
+ this . _completeEnter ( ) ;
181
+ } else {
182
+ // Guarantees that the animation-related events will
183
+ // fire even if something interrupts the animation.
184
+ clearTimeout ( this . _enterFallback ) ;
185
+ this . _enterFallback = setTimeout ( this . _completeEnter , 200 ) ;
186
+ }
197
187
}
198
188
}
199
189
200
190
/** Begin animation of the snack bar exiting from view. */
201
191
exit ( ) : Observable < void > {
202
- // It's common for snack bars to be opened by random outside calls like HTTP requests or
203
- // errors. Run inside the NgZone to ensure that it functions correctly.
204
- this . _ngZone . run ( ( ) => {
205
- // Note: this one transitions to `hidden`, rather than `void`, in order to handle the case
206
- // where multiple snack bars are opened in quick succession (e.g. two consecutive calls to
207
- // `MatSnackBar.open`).
208
- this . _animationState = 'hidden' ;
209
- this . _changeDetectorRef . markForCheck ( ) ;
210
-
211
- // Mark this element with an 'exit' attribute to indicate that the snackbar has
212
- // been dismissed and will soon be removed from the DOM. This is used by the snackbar
213
- // test harness.
214
- this . _elementRef . nativeElement . setAttribute ( 'mat-exit' , '' ) ;
215
-
216
- // If the snack bar hasn't been announced by the time it exits it wouldn't have been open
217
- // long enough to visually read it either, so clear the timeout for announcing.
218
- clearTimeout ( this . _announceTimeoutId ) ;
219
- } ) ;
192
+ // Mark this element with an 'exit' attribute to indicate that the snackbar has
193
+ // been dismissed and will soon be removed from the DOM. This is used by the snackbar
194
+ // test harness.
195
+ this . _elementRef . nativeElement . setAttribute ( 'mat-exit' , '' ) ;
196
+
197
+ // If the snack bar hasn't been announced by the time it exits it wouldn't have been open
198
+ // long enough to visually read it either, so clear the timeout for announcing.
199
+ clearTimeout ( this . _announceTimeoutId ) ;
200
+
201
+ if ( this . _animationsDisabled ) {
202
+ // It's common for snack bars to be opened by random outside calls like HTTP requests or
203
+ // errors. Run inside the NgZone to ensure that it functions correctly.
204
+ this . _ngZone . run ( this . _completeExit ) ;
205
+ } else {
206
+ // Guarantees that the animation-related events will
207
+ // fire even if something interrupts the animation.
208
+ clearTimeout ( this . _exitFallback ) ;
209
+ this . _exitFallback = setTimeout ( this . _completeExit , 150 ) ;
210
+ }
220
211
221
212
return this . _onExit ;
222
213
}
223
214
224
215
/** Makes sure the exit callbacks have been invoked when the element is destroyed. */
225
216
ngOnDestroy ( ) {
217
+ clearTimeout ( this . _enterFallback ) ;
226
218
this . _destroyed = true ;
227
219
this . _clearFromModals ( ) ;
228
220
this . _completeExit ( ) ;
229
221
}
230
222
223
+ private _completeEnter = ( ) => {
224
+ clearTimeout ( this . _enterFallback ) ;
225
+ this . _ngZone . run ( ( ) => {
226
+ this . _onEnter . next ( ) ;
227
+ this . _onEnter . complete ( ) ;
228
+ } ) ;
229
+ } ;
230
+
231
231
/**
232
232
* Removes the element in a microtask. Helps prevent errors where we end up
233
233
* removing an element which is in the middle of an animation.
234
234
*/
235
- private _completeExit ( ) {
235
+ private _completeExit = ( ) => {
236
+ clearTimeout ( this . _exitFallback ) ;
236
237
queueMicrotask ( ( ) => {
237
238
this . _onExit . next ( ) ;
238
239
this . _onExit . complete ( ) ;
239
240
} ) ;
240
- }
241
+ } ;
241
242
242
243
/**
243
244
* Called after the portal contents have been attached. Can be
0 commit comments