@@ -37,7 +37,15 @@ import {
37
37
ViewEncapsulation ,
38
38
} from '@angular/core' ;
39
39
import { fromEvent , merge , Observable , Subject } from 'rxjs' ;
40
- import { debounceTime , filter , map , startWith , take , takeUntil } from 'rxjs/operators' ;
40
+ import {
41
+ debounceTime ,
42
+ filter ,
43
+ map ,
44
+ startWith ,
45
+ take ,
46
+ takeUntil ,
47
+ distinctUntilChanged ,
48
+ } from 'rxjs/operators' ;
41
49
import { matDrawerAnimations } from './drawer-animations' ;
42
50
import { ANIMATION_MODULE_TYPE } from '@angular/platform-browser/animations' ;
43
51
@@ -108,8 +116,8 @@ export class MatDrawerContent extends CdkScrollable implements AfterContentInit
108
116
host : {
109
117
'class' : 'mat-drawer' ,
110
118
'[@transform]' : '_animationState' ,
111
- '(@transform.start)' : '_onAnimationStart ($event)' ,
112
- '(@transform.done)' : '_onAnimationEnd ($event)' ,
119
+ '(@transform.start)' : '_animationStarted.next ($event)' ,
120
+ '(@transform.done)' : '_animationEnd.next ($event)' ,
113
121
// must prevent the browser from aligning text based on value
114
122
'[attr.align]' : 'null' ,
115
123
'[class.mat-drawer-end]' : 'position === "end"' ,
@@ -166,7 +174,10 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
166
174
private _openedVia : FocusOrigin | null ;
167
175
168
176
/** Emits whenever the drawer has started animating. */
169
- _animationStarted = new EventEmitter < AnimationEvent > ( ) ;
177
+ _animationStarted = new Subject < AnimationEvent > ( ) ;
178
+
179
+ /** Emits whenever the drawer is done animating. */
180
+ _animationEnd = new Subject < AnimationEvent > ( ) ;
170
181
171
182
/** Current state of the sidenav animation. */
172
183
_animationState : 'open-instant' | 'open' | 'void' = 'void' ;
@@ -255,6 +266,19 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
255
266
event . stopPropagation ( ) ;
256
267
} ) ) ;
257
268
} ) ;
269
+
270
+ // We need a Subject with distinctUntilChanged, because the `done` event
271
+ // fires twice on some browsers. See https://github.com/angular/angular/issues/24084
272
+ this . _animationEnd . pipe ( distinctUntilChanged ( ( x , y ) => {
273
+ return x . fromState === y . fromState && x . toState === y . toState ;
274
+ } ) ) . subscribe ( ( event : AnimationEvent ) => {
275
+ const { fromState, toState} = event ;
276
+
277
+ if ( ( toState . indexOf ( 'open' ) === 0 && fromState === 'void' ) ||
278
+ ( toState === 'void' && fromState . indexOf ( 'open' ) === 0 ) ) {
279
+ this . openedChange . emit ( this . _opened ) ;
280
+ }
281
+ } ) ;
258
282
}
259
283
260
284
/** Traps focus inside the drawer. */
@@ -314,6 +338,9 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
314
338
if ( this . _focusTrap ) {
315
339
this . _focusTrap . destroy ( ) ;
316
340
}
341
+
342
+ this . _animationStarted . complete ( ) ;
343
+ this . _animationEnd . complete ( ) ;
317
344
}
318
345
319
346
/**
@@ -367,19 +394,6 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
367
394
} ) ;
368
395
}
369
396
370
- _onAnimationStart ( event : AnimationEvent ) {
371
- this . _animationStarted . emit ( event ) ;
372
- }
373
-
374
- _onAnimationEnd ( event : AnimationEvent ) {
375
- const { fromState, toState} = event ;
376
-
377
- if ( ( toState . indexOf ( 'open' ) === 0 && fromState === 'void' ) ||
378
- ( toState === 'void' && fromState . indexOf ( 'open' ) === 0 ) ) {
379
- this . openedChange . emit ( this . _opened ) ;
380
- }
381
- }
382
-
383
397
get _width ( ) : number {
384
398
return this . _elementRef . nativeElement ? ( this . _elementRef . nativeElement . offsetWidth || 0 ) : 0 ;
385
399
}
0 commit comments