如何从所有消息的可观察对象中创建未读消息的可观察对象

时间:2016-07-21 11:49:13

标签: angular reactive-programming rxjs rxjs5

有一个websocket echo服务,用于发送和接收消息:

@Injectable()
export class NotificationsService {
  private ws = new $WebSocket('wss://echo.websocket.org');

  wsSendMessage(message: string = `Message ${Math.random()}`): void {
    this.ws.send(message);
  }

  wsGetMessages(): Observable<string> {
    return Observable.from(this.ws.getDataStream())
      .map((res: any) => res.data);
  }
}

通知组件订阅此observable并显示通知下拉列表中的所有消息:

  getMessages(): void {
    this.notificationsService.wsGetMessages().subscribe(
        (message: string) => {
          this.messages.unshift(message);
        },
        (err: any) => console.log(err)
    );    
  }

当打开通知下拉列表面板时,我需要在导航栏组件中显示未读消息的数量并将其设置为0。我对如何做到没有任何想法,所以我需要你的帮助...

P.S。

现在,websocket echo服务是:

@Injectable()
export class NotificationsService {
  private ws = new $WebSocket('wss://echo.websocket.org');

  wsSendMessage(message: string = `Message ${Math.random()}`): void {
    this.ws.send(message);
  }

  wsGetMessages(): Observable<Object> {
    return Observable.from(this.ws.getDataStream())
      .map((res: any) => res.data);
  }

  messagesReadStream(msgArray: Object[]): Observable<Object> {
    return Observable.from(msgArray);
  }
}

和通知组件是:

export class Notifications implements OnInit {
  messagesAll:string[] = [];
  messagesRead:string[] = [];
  newMessagesNumber:number = 0;

  constructor(private notificationsService: NotificationsService) {
  }

  addMessage(): void {
    this.notificationsService.wsSendMessage();
  }

  getMessages(): void {
    this.notificationsService.wsGetMessages()
      .subscribe(
        (message: any) => this.messagesAll.unshift(message),
        (err: any) => console.error(err)
      );
  }

  readMessages(): void {
    this.messagesRead = this.messagesAll.slice();

    this.notificationsService.messagesReadStream(this.messagesRead)
      .switchMap(() => 
        this.notificationsService
          .wsGetMessages()
          .scan((unread, _) => unread + 1, 0)    
          .startWith(0))
      .subscribe(
        (count: number) => this.newMessagesNumber = count,
        (err: any) => console.error(err)
      );    
  }

  ngOnInit(): void {
    this.getMessages();
  }  
}

使用模板:

<button type="button" class="btn btn-primary-outline btn-sm" (click) = "addMessage()">
  Add message
</button>  

<button type="button" class="btn btn-primary-outline btn-sm" (click) = "readMessages()">
  Read messages
</button>  

<div style="margin-top: 1rem">
  <span class="circle bg-warning fw-bold">
      {{newMessagesNumber}}
  </span>  
</div>

现在,如果点击button 'Add message'我的计数器不会更改0的值。只有当我点击button 'Add message',然后点击button 'Read messages',然后再点击button 'Add message',计数器就会开始正常运行。你能解释一下,问题是什么?

1 个答案:

答案 0 :(得分:2)

您需要多个Observable。一个包含计数,一个用于在读取消息时发出信号。前者将使用wsGetMessage流,而后者必须连接到Observable,只要打开通知面板就会触发。

const panelOpened: Observable<any> = //..Need a signalling mechanism for when the messages get read

const unreadCount: Observable<number> = messagesRead.switchMap(() => 
   this.notificationsService
         .wsGetMessages()
         //Just count all of the messages as they come in.
         .scan((unread, _) => unread + 1, 0)
         //Make sure it always gets reset to zero
         .startWith(0));

//Subscribe to updates on count changes.
unreadCount.subscribe(count => this.unreadMessageCount = count);