Skip to content

Commit 87ab60e

Browse files
committed
feat(snackbar): add afterShow/afterHide observables to MdcSnackbarRef
1 parent d45e341 commit 87ab60e

File tree

4 files changed

+58
-19
lines changed

4 files changed

+58
-19
lines changed

bundle/src/components/snackbar/mdc.snackbar.adapter.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ export interface MdcSnackbarAdapter {
2020
deregisterActionClickHandler: (handler: EventListener) => void;
2121
registerTransitionEndHandler: (handler: EventListener) => void;
2222
deregisterTransitionEndHandler: (handler: EventListener) => void;
23+
notifyShow: () => void;
24+
notifyHide: () => void;
2325
}

bundle/src/components/snackbar/mdc.snackbar.service.ts

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ const CLASS_ALIGN_START = 'mdc-snackbar--align-start';
1414
* It can also be used to subscribe to action clicks.
1515
*/
1616
export class MdcSnackbarRef {
17-
constructor(private _action: Subject<void>) {}
17+
constructor(
18+
private _action: Subject<void>,
19+
private _show: Subject<void>,
20+
private _hide: Subject<void>
21+
) {}
1822

1923
/**
2024
* Subscribe to this observable to be informed when a user clicks the action
@@ -24,6 +28,24 @@ export class MdcSnackbarRef {
2428
action(): Observable<void> {
2529
return this._action.asObservable();
2630
}
31+
32+
/**
33+
* Subscribe to this observable to be informed when the message is displayed.
34+
* Note that the observable will complete when the snackbar disappears from screen,
35+
* so there is no need to unsubscribe.
36+
*/
37+
afterShow(): Observable<void> {
38+
return this._show.asObservable();
39+
}
40+
41+
/**
42+
* Subscribe to this observable to be informed when the message is displayed.
43+
* Note that the observable will complete when the snackbar disappears from screen,
44+
* so there is no need to unsubscribe.
45+
*/
46+
afterHide(): Observable<void> {
47+
return this._hide.asObservable();
48+
}
2749
}
2850

2951
/**
@@ -38,6 +60,7 @@ export class MdcSnackbarService {
3860
private lastActivated = -1;
3961
private lastDismissed = -1;
4062

63+
private openMessage: Subject<number> = new Subject<number>();
4164
private closeMessage: Subject<number> = new Subject<number>();
4265

4366
constructor() {
@@ -69,16 +92,8 @@ export class MdcSnackbarService {
6992
const textEl = root.querySelector('.mdc-snackbar__text');
7093
const buttonEl = <HTMLElement>root.querySelector('.mdc-snackbar__action-button');
7194
const adapter: MdcSnackbarAdapter = {
72-
addClass: (className) => {
73-
if (className === CLASS_ACTIVE)
74-
this.activateNext();
75-
root.classList.add(className);
76-
},
77-
removeClass: (className) => {
78-
if (className === 'mdc-snackbar--active')
79-
this.deactivateLast();
80-
root.classList.remove(className);
81-
},
95+
addClass: (className) => { root.classList.add(className); },
96+
removeClass: (className) => { root.classList.remove(className); },
8297
setAriaHidden: () => root.setAttribute('aria-hidden', 'true'),
8398
unsetAriaHidden: () => root.removeAttribute('aria-hidden'),
8499
setActionAriaHidden: () => buttonEl.setAttribute('aria-hidden', 'true'),
@@ -96,7 +111,9 @@ export class MdcSnackbarService {
96111
registerActionClickHandler: (handler) => buttonEl.addEventListener('click', handler),
97112
deregisterActionClickHandler: (handler) => buttonEl.removeEventListener('click', handler),
98113
registerTransitionEndHandler: (handler) => root.addEventListener(getCorrectEventName(window, 'transitionend'), handler),
99-
deregisterTransitionEndHandler: (handler) => root.removeEventListener(getCorrectEventName(window, 'transitionend'), handler)
114+
deregisterTransitionEndHandler: (handler) => root.removeEventListener(getCorrectEventName(window, 'transitionend'), handler),
115+
notifyShow: () => { this.activateNext(); },
116+
notifyHide: () => { this.deactivateLast(); }
100117
}
101118
return new MDCSnackbarFoundation(adapter);
102119
}
@@ -105,7 +122,7 @@ export class MdcSnackbarService {
105122
while (this.lastDismissed < this.lastActivated)
106123
// since this activates a new message, all messages before will logically be closed:
107124
this.closeMessage.next(++this.lastDismissed);
108-
++this.lastActivated;
125+
this.openMessage.next(++this.lastActivated);
109126
this.isActive = true;
110127
}
111128

@@ -144,21 +161,33 @@ export class MdcSnackbarService {
144161

145162
// provide a means to subscribe to an action click:
146163
let action = new Subject<void>();
164+
let show = new Subject<void>();
165+
let hide = new Subject<void>();
147166
if (message.actionText)
148-
data.actionHandler = function() {action.next(); };
149-
// make sure the action Subject will complete after the snackbar is removed from screen,
150-
// so that callers never have to unsubscribe:
167+
data.actionHandler = function() { action.next(); };
168+
169+
// manage the show subscription
170+
this.openMessage.asObservable().pipe(
171+
filter(nr => nr === messageNr),
172+
take(1)
173+
).subscribe(nr => { show.next(); });
174+
// manage the hide subscription, and close complete all observables when the
175+
// message is removed:
151176
this.closeMessage.asObservable().pipe(
152177
filter(nr => nr === messageNr),
153178
take(1)
154179
).subscribe(nr => {
180+
hide.next();
181+
show.complete();
182+
hide.complete();
155183
action.complete();
156184
});
157185

158-
// show the actual snackbar:
159-
this.snackbar.show(data);
186+
// show the actual snackbar, using setTimeout to give callers
187+
// a chance to subscribe to all events:
188+
setTimeout(() => {this.snackbar.show(data); });
160189

161-
return new MdcSnackbarRef(action);
190+
return new MdcSnackbarRef(action, show, hide);
162191
}
163192

164193
/**

site/src/app/components/snippets/directives/snippet.snackbar.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
</section>
2626
</form>
2727
<section>
28+
<p>Currently Showing: {{currentMessage}}</p>
2829
<p>Last Action: {{lastAction}}</p>
2930
</section>
3031
</fieldset><div class="snippet-skip-line"></div>

site/src/app/components/snippets/directives/snippet.snackbar.component.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export class SnippetSnackbarComponent/*snip:skip*/extends AbstractSnippetCompone
1818
actionText = 'Action';
1919
multiline = false;
2020
actionOnBottom = false;
21+
currentMessage = '<none>';
2122
lastAction = '<none>';
2223

2324
constructor(private snackbar: MdcSnackbarService) {
@@ -44,6 +45,12 @@ export class SnippetSnackbarComponent/*snip:skip*/extends AbstractSnippetCompone
4445
multiline: this.multiline,
4546
actionOnBottom: this.multiline && this.actionOnBottom
4647
});
48+
snackbarRef.afterShow().subscribe(() => {
49+
this.currentMessage = '\'' + message + '\'';
50+
});
51+
snackbarRef.afterHide().subscribe(() => {
52+
this.currentMessage = '<none>';
53+
});
4754
snackbarRef.action().subscribe(() => {
4855
this.lastAction = '\'' + action + '\' clicked for snackbar \'' + message + '\'';
4956
});

0 commit comments

Comments
 (0)