Skip to content

Commit 5295e2f

Browse files
crisbetojosephperrott
authored andcommitted
fix(sidenav): opened and closed events emitting twice on IE and Edge (#13649)
1 parent 2006144 commit 5295e2f

File tree

2 files changed

+33
-19
lines changed

2 files changed

+33
-19
lines changed

src/lib/sidenav/drawer.ts

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,15 @@ import {
3737
ViewEncapsulation,
3838
} from '@angular/core';
3939
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';
4149
import {matDrawerAnimations} from './drawer-animations';
4250
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';
4351

@@ -108,8 +116,8 @@ export class MatDrawerContent extends CdkScrollable implements AfterContentInit
108116
host: {
109117
'class': 'mat-drawer',
110118
'[@transform]': '_animationState',
111-
'(@transform.start)': '_onAnimationStart($event)',
112-
'(@transform.done)': '_onAnimationEnd($event)',
119+
'(@transform.start)': '_animationStarted.next($event)',
120+
'(@transform.done)': '_animationEnd.next($event)',
113121
// must prevent the browser from aligning text based on value
114122
'[attr.align]': 'null',
115123
'[class.mat-drawer-end]': 'position === "end"',
@@ -166,7 +174,10 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
166174
private _openedVia: FocusOrigin | null;
167175

168176
/** 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>();
170181

171182
/** Current state of the sidenav animation. */
172183
_animationState: 'open-instant' | 'open' | 'void' = 'void';
@@ -255,6 +266,19 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
255266
event.stopPropagation();
256267
}));
257268
});
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+
});
258282
}
259283

260284
/** Traps focus inside the drawer. */
@@ -314,6 +338,9 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
314338
if (this._focusTrap) {
315339
this._focusTrap.destroy();
316340
}
341+
342+
this._animationStarted.complete();
343+
this._animationEnd.complete();
317344
}
318345

319346
/**
@@ -367,19 +394,6 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr
367394
});
368395
}
369396

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-
383397
get _width(): number {
384398
return this._elementRef.nativeElement ? (this._elementRef.nativeElement.offsetWidth || 0) : 0;
385399
}

src/lib/sidenav/sidenav.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ export class MatSidenavContent extends MatDrawerContent {
6060
'class': 'mat-drawer mat-sidenav',
6161
'tabIndex': '-1',
6262
'[@transform]': '_animationState',
63-
'(@transform.start)': '_onAnimationStart($event)',
64-
'(@transform.done)': '_onAnimationEnd($event)',
63+
'(@transform.start)': '_animationStarted.next($event)',
64+
'(@transform.done)': '_animationEnd.next($event)',
6565
// must prevent the browser from aligning text based on value
6666
'[attr.align]': 'null',
6767
'[class.mat-drawer-end]': 'position === "end"',

0 commit comments

Comments
 (0)