Skip to content

Commit

Permalink
fix(snack-bar): animation not starting for subsequent snack bars (#6649)
Browse files Browse the repository at this point in the history
Since the switch to OnPush change detection, opening a snack bar while another one is open, programmatically isn't guaranteed to actually show the second snack bar, because the user might not hit the zone (e.g. if it's through a timeout). These changes trigger change detection manually on open. I also got rid of a couple of redundant methods on the snack bar container.

Fixes #6222.
  • Loading branch information
crisbeto authored and jelbourn committed Sep 1, 2017
1 parent 89fea50 commit 730e7ae
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 26 deletions.
42 changes: 18 additions & 24 deletions src/lib/snack-bar/snack-bar-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
ElementRef,
ChangeDetectionStrategy,
ViewEncapsulation,
ChangeDetectorRef,
} from '@angular/core';
import {
trigger,
Expand Down Expand Up @@ -63,24 +64,25 @@ export const HIDE_ANIMATION = '195ms cubic-bezier(0.0,0.0,0.2,1)';
},
animations: [
trigger('state', [
state('void', style({transform: 'translateY(100%)'})),
state('initial', style({transform: 'translateY(100%)'})),
state('void, initial, complete', style({transform: 'translateY(100%)'})),
state('visible', style({transform: 'translateY(0%)'})),
state('complete', style({transform: 'translateY(100%)'})),
transition('visible => complete', animate(HIDE_ANIMATION)),
transition('initial => visible, void => visible', animate(SHOW_ANIMATION)),
])
],
})
export class MdSnackBarContainer extends BasePortalHost implements OnDestroy {
/** Whether the component has been destroyed. */
private _destroyed = false;

/** The portal host inside of this container into which the snack bar content will be loaded. */
@ViewChild(PortalHostDirective) _portalHost: PortalHostDirective;

/** Subject for notifying that the snack bar has exited from view. */
private onExit: Subject<any> = new Subject();
_onExit: Subject<any> = new Subject();

/** Subject for notifying that the snack bar has finished entering the view. */
private onEnter: Subject<any> = new Subject();
_onEnter: Subject<any> = new Subject();

/** The state of the snack bar animations. */
animationState: SnackBarState = 'initial';
Expand All @@ -91,7 +93,8 @@ export class MdSnackBarContainer extends BasePortalHost implements OnDestroy {
constructor(
private _ngZone: NgZone,
private _renderer: Renderer2,
private _elementRef: ElementRef) {
private _elementRef: ElementRef,
private _changeDetectorRef: ChangeDetectorRef) {
super();
}

Expand Down Expand Up @@ -126,7 +129,7 @@ export class MdSnackBarContainer extends BasePortalHost implements OnDestroy {
if (event.toState === 'visible') {
// Note: we shouldn't use `this` inside the zone callback,
// because it can cause a memory leak.
const onEnter = this.onEnter;
const onEnter = this._onEnter;

this._ngZone.run(() => {
onEnter.next();
Expand All @@ -137,30 +140,21 @@ export class MdSnackBarContainer extends BasePortalHost implements OnDestroy {

/** Begin animation of snack bar entrance into view. */
enter(): void {
this.animationState = 'visible';
}

/** Returns an observable resolving when the enter animation completes. */
_onEnter(): Observable<void> {
this.animationState = 'visible';
return this.onEnter.asObservable();
if (!this._destroyed) {
this.animationState = 'visible';
this._changeDetectorRef.detectChanges();
}
}

/** Begin animation of the snack bar exiting from view. */
exit(): Observable<void> {
this.animationState = 'complete';
return this._onExit();
return this._onExit;
}

/** Returns an observable that completes after the closing animation is done. */
_onExit(): Observable<void> {
return this.onExit.asObservable();
}

/**
* Makes sure the exit callbacks have been invoked when the element is destroyed.
*/
/** Makes sure the exit callbacks have been invoked when the element is destroyed. */
ngOnDestroy() {
this._destroyed = true;
this._completeExit();
}

Expand All @@ -171,7 +165,7 @@ export class MdSnackBarContainer extends BasePortalHost implements OnDestroy {
private _completeExit() {
// Note: we shouldn't use `this` inside the zone callback,
// because it can cause a memory leak.
const onExit = this.onExit;
const onExit = this._onExit;

first.call(this._ngZone.onMicrotaskEmpty).subscribe(() => {
onExit.next();
Expand Down
4 changes: 2 additions & 2 deletions src/lib/snack-bar/snack-bar-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class MdSnackBarRef<T> {
this.containerInstance = containerInstance;
// Dismiss snackbar on action.
this.onAction().subscribe(() => this.dismiss());
containerInstance._onExit().subscribe(() => this._finishDismiss());
containerInstance._onExit.subscribe(() => this._finishDismiss());
}

/** Dismisses the snack bar. */
Expand Down Expand Up @@ -90,7 +90,7 @@ export class MdSnackBarRef<T> {

/** Gets an observable that is notified when the snack bar has opened and appeared. */
afterOpened(): Observable<void> {
return this.containerInstance._onEnter();
return this.containerInstance._onEnter;
}

/** Gets an observable that is notified when the snack bar action is called. */
Expand Down

0 comments on commit 730e7ae

Please sign in to comment.