具有多个订阅者的 Angular 2 Observable [英] Angular 2 Observable with multiple subscribers

查看:25
本文介绍了具有多个订阅者的 Angular 2 Observable的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个从 API 获取数据的 angular 2 服务该服务有 3 个订阅者(在组件中定义),每个订阅者都用数据做其他事情(不同的图表)

我注意到我正在向 API 发出三个 GET 请求,而我想要实现的是一个请求,并且订阅者将共享数据我研究了 HOT 和 COLD observable 并在 observable 上尝试了 .share() 但我仍然在做 3 个单独的调用

更新,添加代码

<块引用>

服务

import { Injectable } from '@angular/core';从@angular/http"导入 { Http, Response };从 'rxjs/Rx' 导入 {Observable};//导入 RxJs 所需的方法导入 'rxjs/add/operator/map';导入 'rxjs/add/operator/catch';从'./model/StationCompliance'导入{StationCompliance};@Injectable()出口类 StationComplianceService {私人网址 = '/api/read/stations';构造函数(私有http:Http){console.log('启动站合规服务');}getStationCompliance() : Observable{返回 this.http.get(this.url).map((res:Response) => res.json()).catch((error:any) => Observable.throw(error.json().error || '服务器错误'));}}

<块引用>

组件 1

import { Component, OnInit } from '@angular/core';从 'angular2-highcharts' 导入 { CHART_DIRECTIVES };从'../station-compliance.service'导入{ StationComplianceService};@零件({选择器:'app-up-down-graph',templateUrl: './up-down-graph.component.html',styleUrls: ['./up-down-graph.component.css']})导出类 UpDownGraphComponent 实现 OnInit {图数据;错误消息:字符串;选项;构造函数(私人车站服务:StationComplianceService){}ngOnInit() {this.getStationTypes();}getStationTypes(){this.stationService.getStationCompliance().订阅(图数据 =>{this.graphData = graphData;this.options = {图表:{类型:'饼',情节阴影:真实},绘图选项:{showInLegend: 真},标题:{文本:'上下设备'},系列: [{数据:this.processStationType(this.graphData)}]}},错误 =>this.errorMessage = <any>error);}

其他两个组件几乎一样,只是显示其他图形

解决方案

我遇到了类似的问题,并使用 Aran 的建议解决了它,参考了 Cory Rylan 的 Angular 2 Observable Data Services 博客文章.对我来说,关键是使用 BehaviorSubject.以下是最终对我有用的代码片段.

数据服务:

数据服务创建一个内部BehaviorSubject,在服务初始化时缓存一次数据.消费者使用 subscribeToDataService() 方法来访问数据.

 import { Injectable } from '@angular/core';从@angular/http"导入 { Http, Response };从 'rxjs/BehaviorSubject' 导入 { BehaviorSubject };从 'rxjs/Observable' 导入 { Observable };从'./data'导入{数据};从'../../properties'导入{属性};@Injectable()导出类数据服务{allData: Data[] = new Array();allData$: BehaviorSubject;构造函数(私有http:Http){this.initializeDataService();}初始化数据服务(){如果 (!this.allData$) {this.allData$ = <BehaviorSubject<Data[]>>新行为主题(新数组<数据>());this.http.get(properties.DATA_API).map(this.extractData).catch(this.handleError).订阅(所有数据 =>{this.allData = allData;this.allData$.next(allData);},错误 =>console.log("订阅数据服务时出错:" + 错误));}}subscribeToDataService(): Observable{返回 this.allData$.asObservable();}//其他方法已省略}

零件:

组件可以在初始化时订阅数据服务.

 导出类 TestComponent 实现 OnInit {allData$: Observable;构造函数(私有数据服务:数据服务){}ngOnInit() {this.allData$ = this.dataService.subscribeToDataService();}}

组件模板:

然后模板可以根据需要使用异步管道迭代可观察对象.

 *ngFor="let data of allData$ | async"

每次在数据服务中的 BehaviorSubject 上调用 next() 方法时都会更新订阅者.

I have an angular 2 service that fetch data from an API this service has 3 subscribers (defined in Components) each doing something else with the data (different graphs)

I'm noticing that I'm doing three GET requests to the API while what i want to achieve is one request and that the subscribers will share the data I've looks into HOT and COLD observable and tried the .share() on the observable but I'm still doing 3 individual calls

Update, adding code

Service

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';

import {Observable} from 'rxjs/Rx';

// Import RxJs required methods
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

import { StationCompliance } from './model/StationCompliance';


@Injectable()
export class StationComplianceService {

  private url = '/api/read/stations';

  constructor(private http : Http) {
    console.log('Started Station compliance service');
   }

   getStationCompliance() : Observable<StationCompliance []> {
     return this.http.get(this.url)
      .map((res:Response) => res.json())
      .catch((error:any) => Observable.throw(error.json().error || 'Server Error'));
   }
}

Component 1

import { Component, OnInit } from '@angular/core';
import { CHART_DIRECTIVES } from 'angular2-highcharts';

import { StationComplianceService } from '../station-compliance.service';


@Component({
  selector: 'app-up-down-graph',
  templateUrl: './up-down-graph.component.html',
  styleUrls: ['./up-down-graph.component.css']
})
export class UpDownGraphComponent implements OnInit {

  graphData;

  errorMessage: string;

  options;

  constructor(private stationService : StationComplianceService) { }

  ngOnInit() {
    this.getStationTypes();
  }

  getStationTypes(){
    this.stationService.getStationCompliance()
      .subscribe(
        graphData => {
          this.graphData = graphData;
          this.options = {
            chart : {type: 'pie',
                    plotShadow: true
            },
            plotOptions : {
              showInLegend: true
            },
            title : {text: 'Up and Down devices'},
            series: [{
              data: this.processStationType(this.graphData)
            }]
          }
        },
        error => this.errorMessage = <any>error
      );
  }

Other two components are almost the same, they just show other graph

解决方案

I encountered a similar problem and solved it using Aran's suggestion to reference Cory Rylan's Angular 2 Observable Data Services blog post. The key for me was using BehaviorSubject. Here's the snippets of the code that ultimately worked for me.

Data Service:

The data service creates an internal BehaviorSubject to cache the data once when the service is initialized. Consumers use the subscribeToDataService() method to access the data.

    import { Injectable } from '@angular/core';
    import { Http, Response } from '@angular/http';

    import { BehaviorSubject } from 'rxjs/BehaviorSubject';
    import { Observable } from 'rxjs/Observable';

    import { Data } from './data';
    import { properties } from '../../properties';

    @Injectable()
    export class DataService {
      allData: Data[] = new Array<Data>();
      allData$: BehaviorSubject<Data[]>;

      constructor(private http: Http) {
        this.initializeDataService();
      }

      initializeDataService() {
        if (!this.allData$) {
          this.allData$ = <BehaviorSubject<Data[]>> new BehaviorSubject(new Array<Data>());

          this.http.get(properties.DATA_API)
            .map(this.extractData)
            .catch(this.handleError)
            .subscribe(
              allData => {
                this.allData = allData;
                this.allData$.next(allData);
              },
              error => console.log("Error subscribing to DataService: " + error)
            );
        }
      }

      subscribeToDataService(): Observable<Data[]> {
        return this.allData$.asObservable();
      }

      // other methods have been omitted

    }

Component:

Components can subscribe to the data service upon initialization.

    export class TestComponent implements OnInit {
      allData$: Observable<Data[]>;

      constructor(private dataService: DataService) {
      }

      ngOnInit() {
        this.allData$ = this.dataService.subscribeToDataService();
      }

    }

Component Template:

The template can then iterate over the observable as necessary using the async pipe.

    *ngFor="let data of allData$ | async" 

Subscribers are updated each time the next() method is called on the BehaviorSubject in the data service.

这篇关于具有多个订阅者的 Angular 2 Observable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆