I'm building a notifications component which should show notifications to the user. When multiple notifications gets created at once it should queue them.
Right now it shows the first notification just fine, but after that it triggers 2 notifications at the same time (see current output below). It doesn't wait for the previous notification to show and then hide again before showing the next one.
notifications.api.ts:
public notifications = new Subject<INotificationEvent>();
public notifications$ = this.notifications.asObservable();
notifications.component.ts:
private finished = new Subject();
constructor(private notifications: NotificationsApi) {}
zip(this.notificationsApi.notifications$, this.notificationsApi.notifications, (i, s) => s).pipe(
tap(() => {
if (!this.isActive) {
this.finished.next();
}
}),
delayWhen(() => this.finished),
delay(450),
tap((event: INotificationEvent) => {
this.notification = event;
this.isActive = true;
this.cd.markForCheck();
console.log(this.notification);
console.log('showing');
}),
delay(this.hideAfter),
tap(() => {
this.isActive = false;
this.cd.markForCheck();
console.log('closing');
}),
delay(450)
).subscribe(() => {
console.log('finishing');
this.finished.next();
});
app.component.ts:
let i = 0;
setInterval(() => {
this.notifications.newNotification({message: `${i}`, theme: 'primary'});
i++;
}, 2000);
Current output:
{message: "0", theme: "primary"}
showing
closing
finishing
{message: "1", theme: "primary"}
showing
{message: "2", theme: "primary"}
showing
closing
finishing
{message: "3", theme: "primary"}
showing
{message: "4", theme: "primary"}
showing
closing
closing
finishing
finishing
{message: "5", theme: "primary"}
showing
{message: "6", theme: "primary"}
Desired output:
{message: "0", theme: "primary"}
showing
closing
finishing
{message: "1", theme: "primary"}
showing
closing
finishing
{message: "2", theme: "primary"}
showing
closing
finishing
{message: "3", theme: "primary"}
showing
closing
finishing
{message: "4", theme: "primary"}
showing
closing
finishing
{message: "5", theme: "primary"}
showing
closing
finishing
{message: "6", theme: "primary"}
showing
closing
finishing
How can I fix this?
From what you describe it seems to me that you could achieve the same much easily with concatMap
and delay
.
In this example every button click represents one notification. Each notification takes 2s. It depends on what you want to do in the observer but if you don't need the notification at all you can leave it empty (otherwise you'll need probably startWith
). Multiple notifications are queued inside concatMap
and executed one after another.
const notification$ = fromEvent(document.getElementsByTagName('button')[0], 'click');
notification$.pipe(
concatMap(event => of(event).pipe(
tap(v => console.log('showing', v)),
delay(2000),
tap(v => console.log('closing', v)),
))
).subscribe();
Live demo: https://stackblitz.com/edit/rxjs-nqtfzm?file=index.ts