RxJS настраивает Observable для многоадресной рассылки - PullRequest
0 голосов
/ 06 января 2019

Я изо всех сил пытаюсь понять наблюдателя / наблюдателя.

У меня есть приложение Angular, где служба Injectable создает наблюдаемое:

chat.service.ts:

public chatObserver: Observer<any>;
public chatObservable: Observable<any>;
constructor() {
  this.chatObservable = Observable.create((observer: Observer<any>) => {
  this.chatObserver = observer;
  });
}

Когда сообщение получено в chat.service.ts, оно (предположительно) многоадресно:

this.chatObserver.next(chatMessage);

Два компонента подписываются на Observable следующим образом:

constructor(private _chatService: ChatService) {}

ngOnInit() {
    this._chatService.chatObservable.subscribe(
      (message) => {
        console.log('New chat message received!', message)
        // Do something with message
      }
    );

Проблема: только один (последний, кто подписался) получает сообщение.

Вопрос: Как настроить Observable для многоадресной рассылки всем подписчикам?

Ответы [ 2 ]

0 голосов
/ 06 января 2019

Простой переподготовка. Используйте BehaviourSubject, если вы хотите получить некоторые начальные / текущие значения при подписке (вручную в службах / канале и т. Д., Или через асинхронный канал в HTML-шаблонах. Вот базовое предложение того, чего вы пытаетесь достичь. Конечно, есть гораздо больше должно быть сделано с учетом производства. С уважением.

chat.service.ts:

BackEndDB : ChatMessage[] = <Obtain data for chatHistory from your DB>();

Если вы используете какое-либо хранилище BackEnd для своей истории чата, инициализируйте BackEndDB через этот источник, если не let messages$, то будет new BehaviorSubject<ChatMessage[]>(null);. Это не сохранит вашу историю чата, если вы перезагрузите страницу.

messages$ = new BehaviorSubject<ChatMessage[]> // (this.BackEndDB OR null);
sendMessage(message: ChatMessage): void {
  this.BackEndDB.push(message);
  this.messages$.next(this.BackEndDB);
}
getMessages(): Observable<ChatMessage[]> {
  return this.messages$.asObservable();
}

и затем в вашем компоненте:

import {ChatService} from 'yourPath/chat.service'; 

@Component({ 
  selector: 'app-chat',
  templateUrl: ['./chat.component.html'],
  styleUrls: ['./chat.component.css'],
})
export class ChatComponent {
  inbox$: Observable<ChatMessage[]>;
  constructor(private chatService: ChatService) {
    this.inbox$ = this.chatService.getMessages(); 
  } 
  sendMessage(username, msg) {
    let message: ChatMessage = { 
      msg: msg, 
      sender: username 
    }
    this.chatService.sendMessage(message);
  }
} 

, а затем chat.component.html:

<label> Your Name:  </label>
<input type="text" #userName>
<label> Your Message:  </label>
<input type="text" #userMessage>  
<button type="button" (click) = "sendMessage(userName.value,userMessage.value)">Send</button>
<div *ngIf="inbox$ | async; let messages ">
  <div *ngFor= "let message of messages ">
    <p> {{ message.sender  }} </p>
    <p> said: </p>
    <p> {{ message.msg }} </p>
  </div>
</div>

Вы можете создать интерфейс ChatMessage в общей папке, если вы собираетесь использовать его повторно, или непосредственно в своем компоненте, если он используется только там:

interface ChatMessage {
  msg: string;
  sender: string;
}

Единственная причина, по которой мы push добавляем новые сообщения в переменную BackEndDB и затем вызываем следующую, заключается в том, что это простая демонстрация. В действительности вы должны использовать FirestoreCollectionDocument.valueChanges () или любую другую службу данных в реальном времени.

0 голосов
/ 06 января 2019

Вот пример использования многоадресного наблюдателя:

// chat.service.ts:

public chatObserver: Subject<any>;
constructor() {
  this.chatObserver = new Subject();
}

emit chatMessage (у субъекта есть методы next, error и complete):

this.chatObserver.next(chatMessage);

Подписка на компоненты:

constructor(private _chatService: ChatService) {}

ngOnInit() {

  this._chatService.chatObserver.subscribe(
    (message) => {
      console.log('New chat message received!', message)
      // Do something with message
    }
  );

Примечание : Но когда некоторые компоненты подписываются на chatObserver после того, как он отправляет сообщение chatMage, тогда я рекомендую использовать BehaviorSubject вместо Subject (просто замените тему на BehaviorSubject).

BehaviorSubject имеет характеристику, в которой хранится «текущее» значение. Это означает, что вы всегда можете напрямую получить последнее переданное значение из объекта BehaviorSubject (источник / цитата: https://medium.com/@luukgruijs/understanding-rxjs-behaviorsubject-replaysubject-and-asyncsubject-8cc061f1cfc0)

...