2016-08-27 11 views
4

私は複数のコンポーネントが同じサービスを聴きたい角度2を使ってWebアプリケーションを構築しています。このサービスは、websocketからの受信データを返すobservableを返します。私はthisの例に基づいてコードを書いた。角2はコンポーネント間でwebsocketサービスを共有します

現在の問題点は次のとおりです。 データはホームコンポーネントからサービスを通じてサーバーに送信され(WebSocketを使用)、データが返されます。ただし、home.component内のオブザーバだけがnavbarのものではなく、(id:room.createdおよびdataを使用して)呼び出されています。

誰かがなぜ呼び出されないのか教えてもらえますか?また、$ .subscribeというメッセージをapp.componentに追加しようとしましたが、役に立たなかった。

ここでコードを見てみましょう。

オブザーバブルを返すメッセージサービス。このサービスは、メッセージを送受信するコンポーネントによって使用されます。

@Injectable() 
export class MessageService { 
    private _messages: Rx.Subject<Message>; 
    messages$: Rx.Observable<Message>; 

    constructor(wsService: SocketService, private configuration: Configuration) { 
     console.log('messag eservice'); 
     this._messages = <Rx.Subject<Message>>wsService 
     .connect() 
     .map((response: MessageEvent): Message => { 
      let data = JSON.parse(response.data); 
      return { 
       id: data.id, 
       data: data.data, 
      } 
     }); 

     this.messages$ = this._messages.asObservable(); 
    } 

    public send(message: Message): void { 
     this._messages.next(message); 
    } 
} 

websocket接続を作成し、このソケットの入出力にバインドするソケットサービスです。

import { Injectable } from '@angular/core'; 
import * as Rx from "rxjs/Rx"; 
import { Configuration } from '../app.constants'; 

@Injectable() 
export class SocketService { 
    private subject: Rx.Subject<MessageEvent>; 

    constructor(private configuration: Configuration){}; 

    public connect(wsNamespace = ''): Rx.Subject<MessageEvent> { 
     var url = this.configuration.wsUrl + wsNamespace; 
     if(!this.subject) { 
      this.subject = this.create(url); 
     } 
     return this.subject; 
    } 

    private create(url): Rx.Subject<MessageEvent> { 
     let ws = new WebSocket(url); 

     // bind ws events to observable (streams) 
     let observable = Rx.Observable.create((obs: Rx.Observer<MessageEvent>) => { 
      ws.onmessage = obs.next.bind(obs); 
      ws.onerror = obs.error.bind(obs); 
      ws.onclose = obs.complete.bind(obs); 

      return ws.close.bind(ws); 
     }); 

     // on obs next (send something in the stream) send it using ws. 
     let observer = { 
      next: (data: Object) => { 
       if (ws.readyState === WebSocket.OPEN) { 
        ws.send(JSON.stringify(data)); 
       } 
      }, 
     }; 

     return Rx.Subject.create(observer, observable); 
    } 
} 

次プロバイダとアプリケーションのコンポーネント:

providers: [MessageService, SocketService, Configuration, AuthService] 

私はメッセージとソケットサービスが2回インスタンスされていないことを確認するために私のメインapp.componentでプロバイダをインスタンス化しています。

マイhome.componentは、この(これはルーティングを使用してロードされているページです)のようになります。

import { Component, OnInit } from '@angular/core'; 
import { MessageService } from '../../services/message.service'; 

@Component({ 
    moduleId: module.id, 
    selector: 'navbar', 
    templateUrl: 'navbar.component.html', 
    styleUrls: ['navbar.component.css'] 
}) 
export class Navbar implements OnInit { 

    constructor(private messageService: MessageService) { } 

    ngOnInit() { 

    this.messageService.messages$.subscribe(msg => { 
     console.log(msg); 
     if(msg.id == 'room.created') { 
      // navigate naar games! 
     } 
    }); 
    } 

} 

答えて

6

それはあなたのようだ:私のナビゲーションバーのコンポーネントは、この(ディレクティブ)のように見えます

import { Component, OnInit } from '@angular/core'; 
import { Subject } from 'rxjs'; 
import { Router } from '@angular/router'; 
import { MessageService } from '../../services/message.service'; 

@Component({ 
    ... 
    providers: [] 
}) 
export class HomeComponent implements OnInit { 
    constructor(private router: Router, private messageService: MessageService) {} 

    ngOnInit(): void { 
    this.messageService.send({ 
     id: 'room.create', 
     data: {'name': 'Blaat'} 
    }); 

    this.messageService.messages$.subscribe(msg => { 
     console.log(msg); 
     if(msg.id == 'room.created') { 
      // navigate naar games! 
     } 
    }); 
    } 

} 

observable create関数は複数回、おそらく2つのコンポーネント=> 2つのサブスクリプション=> 2つのobservable create function invocationsと呼ばれます。したがって、最新のobservable create fnは、websocket onmessage、onerrorおよびoncloseに対する以前の観測可能なコールバックをオーバーライドします。そのことを防ぐために、基になるobservableをマルチキャストする必要があります(共有オペレータはこのトリックを行うべきです)。これを行う方法の

 // bind ws events to observable (streams) 
     let observable = Rx.Observable.create((obs: Rx.Observer<MessageEvent>) => { 
      ws.onmessage = obs.next.bind(obs); 
      ws.onerror = obs.error.bind(obs); 
      ws.onclose = obs.complete.bind(obs); 

      return ws.close.bind(ws); 
     }).share(); 

もっと便利なリソースが適切に https://github.com/ReactiveX/rxjs/blob/master/src/observable/dom/WebSocketSubject.ts https://github.com/blesh/RxSocketSubject

+0

ありがとうございました!私の観測に共有メソッドを追加することで問題は解決しました。その小さな方法は私に約3時間かかりました:)。私はobservablesを初めて使用しています。このセットアップは、サービスのソケット接続を作成するのに適していると思いますか?特に、ソケット接続を残りのサービスロジック(メッセージサービスとソケットサービス)から分離したい場合 – Bram

+1

私は助けることができてうれしいです。私はこの質問についてもっとお手伝いできるとは思っていませんでしたが、私は答えを更新し、これをどうやって実装するか、どのパッケージを使うことができるかという有益な情報源を追加しました。 –

関連する問題