From f7d3023b092440ad49d6b49bfbca7b3b164433db Mon Sep 17 00:00:00 2001 From: Jeremy Elbourn Date: Tue, 6 Nov 2018 16:57:07 -0800 Subject: [PATCH] Revert "Revert "fix(tabs): duplicate animation events on some browsers (#13674)" (#14015)" This reverts commit 11c96d65a1b644b631034d4d8788a72a4a8cdd2d. Turns out the original change wasn't actually the problem. It was #13888 instead. --- src/lib/tabs/tab-body.html | 2 +- src/lib/tabs/tab-body.ts | 38 ++++++++++++++++++++-------------- src/lib/tabs/tab-group.spec.ts | 2 +- src/lib/tabs/tab-group.ts | 9 ++++---- 4 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/lib/tabs/tab-body.html b/src/lib/tabs/tab-body.html index 03ecd603fd3d..f7fda5137c16 100644 --- a/src/lib/tabs/tab-body.html +++ b/src/lib/tabs/tab-body.html @@ -4,6 +4,6 @@ params: {animationDuration: animationDuration} }" (@translateTab.start)="_onTranslateTabStarted($event)" - (@translateTab.done)="_onTranslateTabComplete($event)"> + (@translateTab.done)="_translateTabComplete.next($event)"> diff --git a/src/lib/tabs/tab-body.ts b/src/lib/tabs/tab-body.ts index d64ccd2fae9a..2073372b560a 100644 --- a/src/lib/tabs/tab-body.ts +++ b/src/lib/tabs/tab-body.ts @@ -28,9 +28,9 @@ import { import {AnimationEvent} from '@angular/animations'; import {TemplatePortal, CdkPortalOutlet, PortalHostDirective} from '@angular/cdk/portal'; import {Directionality, Direction} from '@angular/cdk/bidi'; -import {Subscription} from 'rxjs'; +import {Subscription, Subject} from 'rxjs'; import {matTabsAnimations} from './tabs-animations'; -import {startWith} from 'rxjs/operators'; +import {startWith, distinctUntilChanged} from 'rxjs/operators'; /** * These position states are used internally as animation states for the tab body. Setting the @@ -125,6 +125,9 @@ export class MatTabBody implements OnInit, OnDestroy { /** Tab body position state. Used by the animation trigger for the current state. */ _position: MatTabBodyPositionState; + /** Emits when an animation on the tab is complete. */ + _translateTabComplete = new Subject(); + /** Event emitted when the tab begins to animate towards the center as the active tab. */ @Output() readonly _onCentering: EventEmitter = new EventEmitter(); @@ -171,6 +174,21 @@ export class MatTabBody implements OnInit, OnDestroy { changeDetectorRef.markForCheck(); }); } + + // Ensure that we get unique animation events, because the `.done` callback can get + // invoked twice in some browsers. See https://github.com/angular/angular/issues/24084. + this._translateTabComplete.pipe(distinctUntilChanged((x, y) => { + return x.fromState === y.fromState && x.toState === y.toState; + })).subscribe(event => { + // If the transition to the center is complete, emit an event. + if (this._isCenterPosition(event.toState) && this._isCenterPosition(this._position)) { + this._onCentered.emit(); + } + + if (this._isCenterPosition(event.fromState) && !this._isCenterPosition(this._position)) { + this._afterLeavingCenter.emit(); + } + }); } /** @@ -185,27 +203,17 @@ export class MatTabBody implements OnInit, OnDestroy { ngOnDestroy() { this._dirChangeSubscription.unsubscribe(); + this._translateTabComplete.complete(); } - _onTranslateTabStarted(e: AnimationEvent): void { - const isCentering = this._isCenterPosition(e.toState); + _onTranslateTabStarted(event: AnimationEvent): void { + const isCentering = this._isCenterPosition(event.toState); this._beforeCentering.emit(isCentering); if (isCentering) { this._onCentering.emit(this._elementRef.nativeElement.clientHeight); } } - _onTranslateTabComplete(e: AnimationEvent): void { - // If the transition to the center is complete, emit an event. - if (this._isCenterPosition(e.toState) && this._isCenterPosition(this._position)) { - this._onCentered.emit(); - } - - if (this._isCenterPosition(e.fromState) && !this._isCenterPosition(this._position)) { - this._afterLeavingCenter.emit(); - } - } - /** The text direction of the containing app. */ _getLayoutDirection(): Direction { return this._dir && this._dir.value === 'rtl' ? 'rtl' : 'ltr'; diff --git a/src/lib/tabs/tab-group.spec.ts b/src/lib/tabs/tab-group.spec.ts index cf23ea453a16..0fdf1f0c374e 100644 --- a/src/lib/tabs/tab-group.spec.ts +++ b/src/lib/tabs/tab-group.spec.ts @@ -225,7 +225,7 @@ describe('MatTabGroup', () => { fixture.detectChanges(); tick(); - expect(fixture.componentInstance.animationDone).toHaveBeenCalled(); + expect(fixture.componentInstance.animationDone).toHaveBeenCalledTimes(1); })); it('should add the proper `aria-setsize` and `aria-posinset`', () => { diff --git a/src/lib/tabs/tab-group.ts b/src/lib/tabs/tab-group.ts index d7b9ac4cf5df..241608397ebc 100644 --- a/src/lib/tabs/tab-group.ts +++ b/src/lib/tabs/tab-group.ts @@ -328,15 +328,16 @@ export class MatTabGroup extends _MatTabGroupMixinBase implements AfterContentIn /** Removes the height of the tab body wrapper. */ _removeTabBodyWrapperHeight(): void { - this._tabBodyWrapperHeight = this._tabBodyWrapper.nativeElement.clientHeight; - this._tabBodyWrapper.nativeElement.style.height = ''; + const wrapper = this._tabBodyWrapper.nativeElement; + this._tabBodyWrapperHeight = wrapper.clientHeight; + wrapper.style.height = ''; this.animationDone.emit(); } /** Handle click events, setting new selected index if appropriate. */ - _handleClick(tab: MatTab, tabHeader: MatTabHeader, idx: number) { + _handleClick(tab: MatTab, tabHeader: MatTabHeader, index: number) { if (!tab.disabled) { - this.selectedIndex = tabHeader.focusIndex = idx; + this.selectedIndex = tabHeader.focusIndex = index; } }