Skip to content

Commit

Permalink
fix(expansion-panel): emitting events twice on some browsers (#13600)
Browse files Browse the repository at this point in the history
  • Loading branch information
crisbeto authored and josephperrott committed Oct 19, 2018
1 parent c271167 commit 85a3ae0
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/lib/expansion/expansion-panel.html
Expand Up @@ -2,7 +2,7 @@
<div class="mat-expansion-panel-content"
role="region"
[@bodyExpansion]="_getExpandedState()"
(@bodyExpansion.done)="_bodyAnimation($event)"
(@bodyExpansion.done)="_bodyAnimationDone.next($event)"
[attr.aria-labelledby]="_headerId"
[id]="id"
#body>
Expand Down
31 changes: 19 additions & 12 deletions src/lib/expansion/expansion-panel.ts
Expand Up @@ -35,7 +35,7 @@ import {
import {DOCUMENT} from '@angular/common';
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';
import {Subject} from 'rxjs';
import {filter, startWith, take} from 'rxjs/operators';
import {filter, startWith, take, distinctUntilChanged} from 'rxjs/operators';
import {matExpansionAnimations} from './expansion-animations';
import {MatExpansionPanelContent} from './expansion-panel-content';
import {MAT_ACCORDION, MatAccordionBase} from './accordion-base';
Expand Down Expand Up @@ -119,6 +119,9 @@ export class MatExpansionPanel extends CdkAccordionItem implements AfterContentI
/** ID for the associated header element. Used for a11y labelling. */
_headerId = `mat-expansion-panel-header-${uniqueId++}`;

/** Stream of body animation done events. */
_bodyAnimationDone = new Subject<AnimationEvent>();

constructor(@Optional() @SkipSelf() @Inject(MAT_ACCORDION) accordion: MatAccordionBase,
_changeDetectorRef: ChangeDetectorRef,
_uniqueSelectionDispatcher: UniqueSelectionDispatcher,
Expand All @@ -129,6 +132,20 @@ export class MatExpansionPanel extends CdkAccordionItem implements AfterContentI
super(accordion, _changeDetectorRef, _uniqueSelectionDispatcher);
this.accordion = accordion;
this._document = _document;

// We need a Subject with distinctUntilChanged, because the `done` event
// fires twice on some browsers. See https://github.com/angular/angular/issues/24084
this._bodyAnimationDone.pipe(distinctUntilChanged((x, y) => {
return x.fromState === y.fromState && x.toState === y.toState;
})).subscribe(event => {
if (event.fromState !== 'void') {
if (event.toState === 'expanded') {
this.afterExpand.emit();
} else if (event.toState === 'collapsed') {
this.afterCollapse.emit();
}
}
});
}

/** Determines whether the expansion panel should have spacing between it and its siblings. */
Expand Down Expand Up @@ -166,20 +183,10 @@ export class MatExpansionPanel extends CdkAccordionItem implements AfterContentI

ngOnDestroy() {
super.ngOnDestroy();
this._bodyAnimationDone.complete();
this._inputChanges.complete();
}

_bodyAnimation(event: AnimationEvent) {
const {phaseName, toState, fromState} = event;

if (phaseName === 'done' && toState === 'expanded' && fromState !== 'void') {
this.afterExpand.emit();
}
if (phaseName === 'done' && toState === 'collapsed' && fromState !== 'void') {
this.afterCollapse.emit();
}
}

/** Checks whether the expansion panel's content contains the currently-focused element. */
_containsFocus(): boolean {
if (this._body && this._document) {
Expand Down

0 comments on commit 85a3ae0

Please sign in to comment.