User notification service with rxjs in Angular?

半腔热情 提交于 2020-01-03 02:46:08

问题


I'm relatively new to reactive programming and I'm trying to create an Angular service which can display notifications to the user. So far this is what I have:

https://stackblitz.com/edit/angular-rxjs-notifications?file=app%2Fapp.component.html

But there is a major problem with my implementation that I don't know how to solve: How, in a reactive way, can I queue up notifications? I would like my notification div to appear when the first notification is pushed and when the user clicks "Clear" I would like the div to disappear unless other notifications have been pushed since. That way clear would show the next notification and so on until all notifications have been cleared. Then as soon as a new notification is pushed the div should pop up again.

I chose a Subject in my implementation over a ReplaySubject because I don't want users to see notifications that were pushed while they were loading the next screen but I realized that if I'm using a router inside my app.component.html then I'll run into that behavior anyways. Maybe I need to clear the notification queue when a routing occurs?

Thanks in advance!


回答1:


The example service can look like this

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { merge } from 'rxjs/observable/merge';
import { map, scan } from 'rxjs/operators';

enum ActionType {
  push = 'push',
  pop = 'pop'
}

interface Action {
  type: ActionType;
}

interface PushAction extends Action {
  payload: string;
}

interface PopAction extends Action { }

@Injectable()
export class NotificationService {
  messages$: Observable<string[]>;

  private pushSource = new Subject<string>();
  private popSource = new Subject<void>();

  constructor() {
    const push$ = this.pushSource.asObservable()
      .pipe(map((payload) => ({ type: ActionType.push, payload })));

    const pop$ = this.popSource.asObservable()
      .pipe(map((payload) => ({ type: ActionType.pop })));

    this.messages$ = merge(push$, pop$)
      .pipe(
      scan((acc: any, { payload, type }) => {
        if (type === ActionType.pop) {
          acc = acc.slice(0, -1);
        }
        if (type === ActionType.push) {
          acc = [...acc, payload]
        }
        return acc;
      }, [])
      )
  }

  pushMessage(msg: string) {
    this.pushSource.next(msg)
  }

  popMessage() {
    this.popSource.next()
  }
}

Live demo

We have two streams, pop$ and push$ that we merge together. We than reduce it into a single array using the scan operator.

So a stream of push(hello) -> push(world) -> pop -> push(kitty) would be reduced to [hello, kitty].



来源:https://stackoverflow.com/questions/49907996/user-notification-service-with-rxjs-in-angular

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!