Need a way to subscribe to an observable that Angu

2019-09-05 08:07发布

问题:

I am writing an angular + nodejs application where server listens to twitter stream and front-end angular application using socket.io gets data from server. Everything works till this point, but I am unable to find a way to subscribe to my angular service which using socket.io gets the data. How can I subscribe to the data that my service has and also how can I bind it to my view, so that the data shows up.

Here is my service code in Angular that gets data from server:

import {Injectable} from 'angular2/core';
import {Observer} from 'rxjs/Observer';
import {Observable} from 'rxjs/Observable';
@Injectable()
export class twitterService {
    socket = null;
    tweets$: Observable<string[]>;
    private _tweetObserver : Observer<string>;
    constructor(){
        this.tweets$ = new Observable(observer => this._tweetObserver = observer);
    }
    getTweets() {
        var tweetText: string;
        this.socket = io('http://localhost:8383');
        this.socket.on('twit', function(data){
            tweetText = data; 
        });
        this._tweetObserver.next(tweetText);
    }
}

And here is my Component:

import {Component} from 'angular2/core';
import {Http, HTTP_PROVIDERS} from 'angular2/http';
import {twitterService} from '../Services/Twitter/twitterService';
import {Observable} from 'rxjs/Observable';
import {Observer} from 'rxjs/Observer';
import 'rxjs/add/operator/map';
@Component({
    selector: 'social',
    viewProviders: [HTTP_PROVIDERS],
    providers: [twitterService],
    templateUrl: './components/app/social/social.html'
})
export class socialComponent {
    public tweetsObserver: Observer<string>;
    public tweets$:Observable<string>;
    public tweetsData:string[] = ["Red", "Yellow"];
    items: Array<string>;
    constructor(http: Http, tweets:twitterService) {
        tweets.tweets$.subscribe(tweets => this.items = tweets);
        tweets.getTweets();
    }
}

And here is my view code:

<li *ngFor="#item of items | async">{{item}}</li>

回答1:

You could implement this feature this way:

@Injectable()
export class twitterService {
  socket = null;
  tweets$: Observable<string[]>;
  private _tweetObserver : Observer<string>;
  tweets: string[];

  constructor(){
    this.tweets$ = new Observable(observer => this._tweetObserver = observer);
  }

  getTweets() {
    var tweetText: string;
    this.socket = io('http://localhost:8383');
    this.socket.on('twit', (data) =>{
        this.tweets.push(data);
        this._tweetObserver.next(this.tweets); 
    });
  }
}

This way time a twit is received, the list of twits will be updated in your component. This way you can still use the async operator.

You could also implement such processing in your component and not in the service.

@Injectable()
export class twitterService {
  socket = null;
  tweet$: Observable<string>;
  private _tweetObserver : Observer<string>;

  constructor(){
    this.tweet$ = new Observable(observer => this._tweetObserver = observer);
  }

  getTweets() {
    var tweetText: string;
    this.socket = io('http://localhost:8383');
    this.socket.on('twit', (data) =>{
        this._tweetObserver.next(data); 
    });
  }
}

and the component:

service.$tweet.subscribe((newTwit) => {
  this.tweets.push(newTwit);
});

In this case, this.tweets corresponds a simple array (not an observable) and you don't need to use the async pipe in your ngFor.



回答2:

Collect the tweets in an array and use *ngFor="#tweet of tweets" to bind to the array:

tweets.tweets$.subscribe(tweets => this.items = this.items.concat(tweets));

ohne | async

<li *ngFor="#item of items">{{item}}</li>