diff --git a/src/demo-app/snack-bar/snack-bar-demo.ts b/src/demo-app/snack-bar/snack-bar-demo.ts index 055e752a8f37..344d3ed11eb1 100644 --- a/src/demo-app/snack-bar/snack-bar-demo.ts +++ b/src/demo-app/snack-bar/snack-bar-demo.ts @@ -18,7 +18,7 @@ export class SnackBarDemo { open() { let config = new MdSnackBarConfig(); - config.autoHide = this.autoHide; + config.duration = this.autoHide; this.snackBar.open(this.message, this.action && this.actionButtonLabel, config); } } diff --git a/src/lib/snack-bar/README.md b/src/lib/snack-bar/README.md index 818fdd8bae83..624842573bbd 100644 --- a/src/lib/snack-bar/README.md +++ b/src/lib/snack-bar/README.md @@ -15,7 +15,7 @@ | `viewContainerRef: ViewContainerRef` | The view container ref to attach the snack bar to. | | `role: AriaLivePoliteness = 'assertive'` | The politeness level to announce the snack bar with. | | `announcementMessage: string` | The message to announce with the snack bar. | -| `dismiss: number` | The length of time in milliseconds to wait before autodismissing the snack bar. | +| `duration: number` | The length of time in milliseconds to wait before autodismissing the snack bar. | ### Example diff --git a/src/lib/snack-bar/snack-bar-config.ts b/src/lib/snack-bar/snack-bar-config.ts index 4ebcaa6ef56b..33de8b16f5cc 100644 --- a/src/lib/snack-bar/snack-bar-config.ts +++ b/src/lib/snack-bar/snack-bar-config.ts @@ -15,5 +15,5 @@ export class MdSnackBarConfig { viewContainerRef?: ViewContainerRef = null; /** The length of time in milliseconds to wait before automatically dismissing the snack bar. */ - dismiss?: number = 0; + duration?: number = 0; } diff --git a/src/lib/snack-bar/snack-bar-container.ts b/src/lib/snack-bar/snack-bar-container.ts index f310223ce863..765bc5b18793 100644 --- a/src/lib/snack-bar/snack-bar-container.ts +++ b/src/lib/snack-bar/snack-bar-container.ts @@ -41,7 +41,7 @@ export const HIDE_ANIMATION = '195ms cubic-bezier(0.0,0.0,0.2,1)'; host: { 'role': 'alert', '[@state]': 'animationState', - '(@state.done)': 'markAsExited($event)' + '(@state.done)': 'onAnimationEnd($event)' }, animations: [ trigger('state', [ @@ -58,7 +58,10 @@ export class MdSnackBarContainer extends BasePortalHost { @ViewChild(PortalHostDirective) _portalHost: PortalHostDirective; /** Subject for notifying that the snack bar has exited from view. */ - private _onExit: Subject = new Subject(); + private onExit: Subject = new Subject(); + + /** Subject for notifying that the snack bar has finished entering the view. */ + private onEnter: Subject = new Subject(); /** The state of the snack bar animations. */ animationState: SnackBarState = 'initial'; @@ -87,15 +90,21 @@ export class MdSnackBarContainer extends BasePortalHost { /** Begin animation of the snack bar exiting from view. */ exit(): Observable { this.animationState = 'complete'; - return this._onExit.asObservable(); + return this.onExit.asObservable(); } - /** Mark snack bar as exited from the view. */ - markAsExited(event: AnimationTransitionEvent) { + /** Handle end of animations, updating the state of the snackbar. */ + onAnimationEnd(event: AnimationTransitionEvent) { if (event.toState === 'void' || event.toState === 'complete') { this._ngZone.run(() => { - this._onExit.next(); - this._onExit.complete(); + this.onExit.next(); + this.onExit.complete(); + }); + } + if (event.toState === 'visible') { + this._ngZone.run(() => { + this.onEnter.next(); + this.onEnter.complete(); }); } } @@ -104,4 +113,9 @@ export class MdSnackBarContainer extends BasePortalHost { enter(): void { this.animationState = 'visible'; } + + /** Returns an observable resolving when the enter animation completes. */ + _onEnter(): Observable { + return this.onEnter.asObservable(); + } } diff --git a/src/lib/snack-bar/snack-bar-ref.ts b/src/lib/snack-bar/snack-bar-ref.ts index ebe63bac35c2..21cb7e8bc4a5 100644 --- a/src/lib/snack-bar/snack-bar-ref.ts +++ b/src/lib/snack-bar/snack-bar-ref.ts @@ -19,6 +19,9 @@ export class MdSnackBarRef { /** Subject for notifying the user that the snack bar has closed. */ private _afterClosed: Subject = new Subject(); + /** Subject for notifying the user that the snack bar has opened and appeared. */ + private _afterOpened: Subject; + /** Subject for notifying the user that the snack bar action was called. */ private _onAction: Subject = new Subject(); @@ -51,11 +54,24 @@ export class MdSnackBarRef { } } + /** Marks the snackbar as opened */ + _open(): void { + if (!this._afterOpened.closed) { + this._afterOpened.next(); + this._afterOpened.complete(); + } + } + /** Gets an observable that is notified when the snack bar is finished closing. */ afterDismissed(): Observable { return this._afterClosed.asObservable(); } + /** Gets an observable that is notified when the snack bar has opened and appeared. */ + afterOpened(): Observable { + return this.containerInstance._onEnter(); + } + /** Gets an observable that is notified when the snack bar action is called. */ onAction(): Observable { return this._onAction.asObservable(); diff --git a/src/lib/snack-bar/snack-bar.spec.ts b/src/lib/snack-bar/snack-bar.spec.ts index 3fc39af9be0b..9edb98dd98be 100644 --- a/src/lib/snack-bar/snack-bar.spec.ts +++ b/src/lib/snack-bar/snack-bar.spec.ts @@ -290,7 +290,7 @@ describe('MdSnackBar', () => { it('should dismiss automatically after a specified timeout', fakeAsync(() => { let dismissObservableCompleted = false; let config = new MdSnackBarConfig(); - config.dismiss = 250; + config.duration = 250; let snackBarRef = snackBar.open('content', 'test', config); snackBarRef.afterDismissed().subscribe(null, null, () => { dismissObservableCompleted = true; diff --git a/src/lib/snack-bar/snack-bar.ts b/src/lib/snack-bar/snack-bar.ts index 599da872edf8..db823a81f9d1 100644 --- a/src/lib/snack-bar/snack-bar.ts +++ b/src/lib/snack-bar/snack-bar.ts @@ -63,9 +63,11 @@ export class MdSnackBar { snackBarRef.containerInstance.enter(); } - // TODO(josephperrott): Set dismiss setTimeout after the snackbar finishes entering the view. - if (config.dismiss > 0) { - setTimeout(() => snackBarRef.dismiss(), config.dismiss); + // If a dismiss timeout is provided, set up dismiss based on after the snackbar is opened. + if (config.duration > 0) { + snackBarRef.afterOpened().subscribe(() => { + setTimeout(() => snackBarRef.dismiss(), config.duration); + }); } this._live.announce(config.announcementMessage, config.politeness);