Skip to content

Commit

Permalink
fix(snack-bar): subsequent snack bars not opening; animation issues (#…
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
crisbeto authored and andrewseguin committed Sep 29, 2017
1 parent 6bd6b9f commit 8e77261
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 23 deletions.
24 changes: 8 additions & 16 deletions src/lib/snack-bar/snack-bar-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)';
Expand All @@ -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: [
Expand Down Expand Up @@ -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;
Expand All @@ -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()) {
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down
14 changes: 7 additions & 7 deletions src/lib/snack-bar/snack-bar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'.`);
});

Expand All @@ -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'.`);
});

Expand All @@ -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};
Expand All @@ -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'.`);
});
}));
Expand All @@ -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'.`);
});
});
Expand Down

0 comments on commit 8e77261

Please sign in to comment.