mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(snack-bar): subsequent snack bars not opening; animation issues (#7086)
* Fixes subsequent snack bars not showing up if they are opened while another snack bar is open. This was due to the latter snack bar getting closed immediately, because one of the animation events coming in is `void->void`. * Simplifies the logic for determining the animation state. Using the getter ended up passing returning an invalid state in some cases (e.g. `undefined-top` or `undefined-bottom`). Fixes #7063.
This commit is contained in:
committed by
Andrew Seguin
parent
6bd6b9f1eb
commit
8e7726102b
@@ -38,8 +38,6 @@ import {Subject} from 'rxjs/Subject';
|
||||
import {MatSnackBarConfig} from './snack-bar-config';
|
||||
|
||||
|
||||
export type SnackBarState = 'visible' | 'hidden' | 'void';
|
||||
|
||||
// TODO(jelbourn): we can't use constants from animation.ts here because you can't use
|
||||
// a text interpolation in anything that is analyzed statically with ngc (for AoT compile).
|
||||
export const SHOW_ANIMATION = '225ms cubic-bezier(0.4,0.0,1,1)';
|
||||
@@ -60,7 +58,7 @@ export const HIDE_ANIMATION = '195ms cubic-bezier(0.0,0.0,0.2,1)';
|
||||
host: {
|
||||
'role': 'alert',
|
||||
'class': 'mat-snack-bar-container',
|
||||
'[@state]': 'getAnimationState()',
|
||||
'[@state]': '_animationState',
|
||||
'(@state.done)': 'onAnimationEnd($event)'
|
||||
},
|
||||
animations: [
|
||||
@@ -93,7 +91,7 @@ export class MatSnackBarContainer extends BasePortalHost implements OnDestroy {
|
||||
_onEnter: Subject<any> = new Subject();
|
||||
|
||||
/** The state of the snack bar animations. */
|
||||
private _animationState: SnackBarState;
|
||||
_animationState = 'void';
|
||||
|
||||
/** The snack bar configuration. */
|
||||
snackBarConfig: MatSnackBarConfig;
|
||||
@@ -106,14 +104,6 @@ export class MatSnackBarContainer extends BasePortalHost implements OnDestroy {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current animation state both combining one of the possibilities from
|
||||
* SnackBarState and the vertical location.
|
||||
*/
|
||||
getAnimationState(): string {
|
||||
return `${this._animationState}-${this.snackBarConfig.verticalPosition}`;
|
||||
}
|
||||
|
||||
/** Attach a component portal as content to this snack bar container. */
|
||||
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {
|
||||
if (this._portalHost.hasAttached()) {
|
||||
@@ -146,11 +136,13 @@ export class MatSnackBarContainer extends BasePortalHost implements OnDestroy {
|
||||
|
||||
/** Handle end of animations, updating the state of the snackbar. */
|
||||
onAnimationEnd(event: AnimationEvent) {
|
||||
if (event.toState === 'void' || event.toState.startsWith('hidden')) {
|
||||
const {fromState, toState} = event;
|
||||
|
||||
if ((toState === 'void' && fromState !== 'void') || toState.startsWith('hidden')) {
|
||||
this._completeExit();
|
||||
}
|
||||
|
||||
if (event.toState.startsWith('visible')) {
|
||||
if (toState.startsWith('visible')) {
|
||||
// Note: we shouldn't use `this` inside the zone callback,
|
||||
// because it can cause a memory leak.
|
||||
const onEnter = this._onEnter;
|
||||
@@ -165,14 +157,14 @@ export class MatSnackBarContainer extends BasePortalHost implements OnDestroy {
|
||||
/** Begin animation of snack bar entrance into view. */
|
||||
enter(): void {
|
||||
if (!this._destroyed) {
|
||||
this._animationState = 'visible';
|
||||
this._animationState = `visible-${this.snackBarConfig.verticalPosition}`;
|
||||
this._changeDetectorRef.detectChanges();
|
||||
}
|
||||
}
|
||||
|
||||
/** Begin animation of the snack bar exiting from view. */
|
||||
exit(): Observable<void> {
|
||||
this._animationState = 'hidden';
|
||||
this._animationState = `hidden-${this.snackBarConfig.verticalPosition}`;
|
||||
return this._onExit;
|
||||
}
|
||||
|
||||
|
||||
@@ -186,12 +186,12 @@ describe('MatSnackBar', () => {
|
||||
let snackBarRef = snackBar.open(simpleMessage, undefined, config);
|
||||
|
||||
viewContainerFixture.detectChanges();
|
||||
expect(snackBarRef.containerInstance.getAnimationState())
|
||||
expect(snackBarRef.containerInstance._animationState)
|
||||
.toBe('visible-bottom', `Expected the animation state would be 'visible-bottom'.`);
|
||||
snackBarRef.dismiss();
|
||||
|
||||
viewContainerFixture.detectChanges();
|
||||
expect(snackBarRef.containerInstance.getAnimationState())
|
||||
expect(snackBarRef.containerInstance._animationState)
|
||||
.toBe('hidden-bottom', `Expected the animation state would be 'hidden-bottom'.`);
|
||||
});
|
||||
|
||||
@@ -201,7 +201,7 @@ describe('MatSnackBar', () => {
|
||||
snackBarRef.dismiss();
|
||||
|
||||
viewContainerFixture.detectChanges();
|
||||
expect(snackBarRef.containerInstance.getAnimationState())
|
||||
expect(snackBarRef.containerInstance._animationState)
|
||||
.toBe('hidden-bottom', `Expected the animation state would be 'hidden-bottom'.`);
|
||||
});
|
||||
|
||||
@@ -212,7 +212,7 @@ describe('MatSnackBar', () => {
|
||||
let dismissObservableCompleted = false;
|
||||
|
||||
viewContainerFixture.detectChanges();
|
||||
expect(snackBarRef.containerInstance.getAnimationState())
|
||||
expect(snackBarRef.containerInstance._animationState)
|
||||
.toBe('visible-bottom', `Expected the animation state would be 'visible-bottom'.`);
|
||||
|
||||
let config2 = {viewContainerRef: testViewContainerRef};
|
||||
@@ -225,9 +225,9 @@ describe('MatSnackBar', () => {
|
||||
|
||||
viewContainerFixture.whenStable().then(() => {
|
||||
expect(dismissObservableCompleted).toBe(true);
|
||||
expect(snackBarRef.containerInstance.getAnimationState())
|
||||
expect(snackBarRef.containerInstance._animationState)
|
||||
.toBe('hidden-bottom', `Expected the animation state would be 'hidden-bottom'.`);
|
||||
expect(snackBarRef2.containerInstance.getAnimationState())
|
||||
expect(snackBarRef2.containerInstance._animationState)
|
||||
.toBe('visible-bottom', `Expected the animation state would be 'visible-bottom'.`);
|
||||
});
|
||||
}));
|
||||
@@ -248,7 +248,7 @@ describe('MatSnackBar', () => {
|
||||
|
||||
// Wait for the snackbar open animation to finish.
|
||||
viewContainerFixture.whenStable().then(() => {
|
||||
expect(snackBarRef.containerInstance.getAnimationState())
|
||||
expect(snackBarRef.containerInstance._animationState)
|
||||
.toBe('visible-bottom', `Expected the animation state would be 'visible-bottom'.`);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user