Skip to content

Commit

Permalink
feat(snackbar): add afterShow/afterHide observables to MdcSnackbarRef
Browse files Browse the repository at this point in the history
  • Loading branch information
gjdev committed May 22, 2018
1 parent d45e341 commit 87ab60e
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 19 deletions.
2 changes: 2 additions & 0 deletions bundle/src/components/snackbar/mdc.snackbar.adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ export interface MdcSnackbarAdapter {
deregisterActionClickHandler: (handler: EventListener) => void;
registerTransitionEndHandler: (handler: EventListener) => void;
deregisterTransitionEndHandler: (handler: EventListener) => void;
notifyShow: () => void;
notifyHide: () => void;
}
67 changes: 48 additions & 19 deletions bundle/src/components/snackbar/mdc.snackbar.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ const CLASS_ALIGN_START = 'mdc-snackbar--align-start';
* It can also be used to subscribe to action clicks.
*/
export class MdcSnackbarRef {
constructor(private _action: Subject<void>) {}
constructor(
private _action: Subject<void>,
private _show: Subject<void>,
private _hide: Subject<void>
) {}

/**
* Subscribe to this observable to be informed when a user clicks the action
Expand All @@ -24,6 +28,24 @@ export class MdcSnackbarRef {
action(): Observable<void> {
return this._action.asObservable();
}

/**
* Subscribe to this observable to be informed when the message is displayed.
* Note that the observable will complete when the snackbar disappears from screen,
* so there is no need to unsubscribe.
*/
afterShow(): Observable<void> {
return this._show.asObservable();
}

/**
* Subscribe to this observable to be informed when the message is displayed.
* Note that the observable will complete when the snackbar disappears from screen,
* so there is no need to unsubscribe.
*/
afterHide(): Observable<void> {
return this._hide.asObservable();
}
}

/**
Expand All @@ -38,6 +60,7 @@ export class MdcSnackbarService {
private lastActivated = -1;
private lastDismissed = -1;

private openMessage: Subject<number> = new Subject<number>();
private closeMessage: Subject<number> = new Subject<number>();

constructor() {
Expand Down Expand Up @@ -69,16 +92,8 @@ export class MdcSnackbarService {
const textEl = root.querySelector('.mdc-snackbar__text');
const buttonEl = <HTMLElement>root.querySelector('.mdc-snackbar__action-button');
const adapter: MdcSnackbarAdapter = {
addClass: (className) => {
if (className === CLASS_ACTIVE)
this.activateNext();
root.classList.add(className);
},
removeClass: (className) => {
if (className === 'mdc-snackbar--active')
this.deactivateLast();
root.classList.remove(className);
},
addClass: (className) => { root.classList.add(className); },
removeClass: (className) => { root.classList.remove(className); },
setAriaHidden: () => root.setAttribute('aria-hidden', 'true'),
unsetAriaHidden: () => root.removeAttribute('aria-hidden'),
setActionAriaHidden: () => buttonEl.setAttribute('aria-hidden', 'true'),
Expand All @@ -96,7 +111,9 @@ export class MdcSnackbarService {
registerActionClickHandler: (handler) => buttonEl.addEventListener('click', handler),
deregisterActionClickHandler: (handler) => buttonEl.removeEventListener('click', handler),
registerTransitionEndHandler: (handler) => root.addEventListener(getCorrectEventName(window, 'transitionend'), handler),
deregisterTransitionEndHandler: (handler) => root.removeEventListener(getCorrectEventName(window, 'transitionend'), handler)
deregisterTransitionEndHandler: (handler) => root.removeEventListener(getCorrectEventName(window, 'transitionend'), handler),
notifyShow: () => { this.activateNext(); },
notifyHide: () => { this.deactivateLast(); }
}
return new MDCSnackbarFoundation(adapter);
}
Expand All @@ -105,7 +122,7 @@ export class MdcSnackbarService {
while (this.lastDismissed < this.lastActivated)
// since this activates a new message, all messages before will logically be closed:
this.closeMessage.next(++this.lastDismissed);
++this.lastActivated;
this.openMessage.next(++this.lastActivated);
this.isActive = true;
}

Expand Down Expand Up @@ -144,21 +161,33 @@ export class MdcSnackbarService {

// provide a means to subscribe to an action click:
let action = new Subject<void>();
let show = new Subject<void>();
let hide = new Subject<void>();
if (message.actionText)
data.actionHandler = function() {action.next(); };
// make sure the action Subject will complete after the snackbar is removed from screen,
// so that callers never have to unsubscribe:
data.actionHandler = function() { action.next(); };

// manage the show subscription
this.openMessage.asObservable().pipe(
filter(nr => nr === messageNr),
take(1)
).subscribe(nr => { show.next(); });
// manage the hide subscription, and close complete all observables when the
// message is removed:
this.closeMessage.asObservable().pipe(
filter(nr => nr === messageNr),
take(1)
).subscribe(nr => {
hide.next();
show.complete();
hide.complete();
action.complete();
});

// show the actual snackbar:
this.snackbar.show(data);
// show the actual snackbar, using setTimeout to give callers
// a chance to subscribe to all events:
setTimeout(() => {this.snackbar.show(data); });

return new MdcSnackbarRef(action);
return new MdcSnackbarRef(action, show, hide);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
</section>
</form>
<section>
<p>Currently Showing: {{currentMessage}}</p>
<p>Last Action: {{lastAction}}</p>
</section>
</fieldset><div class="snippet-skip-line"></div>
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export class SnippetSnackbarComponent/*snip:skip*/extends AbstractSnippetCompone
actionText = 'Action';
multiline = false;
actionOnBottom = false;
currentMessage = '<none>';
lastAction = '<none>';

constructor(private snackbar: MdcSnackbarService) {
Expand All @@ -44,6 +45,12 @@ export class SnippetSnackbarComponent/*snip:skip*/extends AbstractSnippetCompone
multiline: this.multiline,
actionOnBottom: this.multiline && this.actionOnBottom
});
snackbarRef.afterShow().subscribe(() => {
this.currentMessage = '\'' + message + '\'';
});
snackbarRef.afterHide().subscribe(() => {
this.currentMessage = '<none>';
});
snackbarRef.action().subscribe(() => {
this.lastAction = '\'' + action + '\' clicked for snackbar \'' + message + '\'';
});
Expand Down

0 comments on commit 87ab60e

Please sign in to comment.