角度-通过Service API调用分配多个可观察数组

时间:2019-05-21 12:51:58

标签: angular rxjs

我有一个服务,该服务调用API以返回可观察的Observable<MeasuringPoint[]>

我希望能够为该服务的结果订阅多个变量。每个变量MeasurementPoints $,MeasuringPointsViewed $,LatestReadings $都需要相同的数据,但是解析方式会有所不同。他们还需要彼此不了解。

有什么最佳方法的想法吗?

3 个答案:

答案 0 :(得分:0)

所以我过去所做的就是创建一个RXJS存储,任何组件都可以注入并使用数据结果。

some-data-store.service.ts

export class SomeDataStoreService {
  // Create a behavior subject that can be changed at will, always houses the "current" value.
  // Allows you to always get the latest emmited value.
  private _measuringPoint = new BehaviorSubject<MeasuringPoint[]>(null);

  // Expose the BeahviorSubject as an observable
  measuringPoint: Observable<MeasuringPoint[]> = this._measuringPoint.asObservable();

  // Inject your api service
  constructor(private measuringPointApi: MeasuringPointApiService) {}

  //Use Api to populate Behavior subject
  getMeasuringPoint() {
    this.measuringPointApi
      .getMeasuringPoint()
      .subscribe(data => this._measuringPoint.next(data));
  }
}

some-consumer.component.ts

export class SomeConsumerComponent implements OnInit {
  MeasuringPoints$: MeasuringPoint[];

  // Inject the DataStoreService
  constructor(private someDataStore: SomeDataStoreService) {}

  ngOnInit() {
    // Request the data initially
    this.someDataStore.getMeasuringPoint();

    // Subscribe to the public member measuringPoint of the dataStoreService.
    // NOTE: You can use this piece over and over in different components, they'll just fire off whenever data is changed.
    this.someDataStore
      .measuringPoint()
      .subscribe(data => (this.MeasuringPoints$ = data));
  }
}

这只是一个示例,您显然需要导入而不需要导入,但这应该可以使您朝正确的方向前进。当然,还有其他方法可以使用,例如NGRX react mui library,但是它是完整的状态管理库。我建议您进行更多研究,然后再研究是否需要像NGRX一样强大的功能。

答案 1 :(得分:0)

我想到了这样的东西:

export class ConsumerComponent implements OnInit {
    mesuringPoint$: Observable<MesurePointModel>;
    mesuringPointView$: Observable<MesurePointModelView>;
    latestReadings$: Observable<number>;

    constructor(private service: DataStoreService) {
        this.mesuringPoint$ = this.service.getData().pipe(// rxjs operators);
        this.mesuringPointView$ = this.service.getData().pipe(// rxjs operators );
        this.latestReadings$ = this.service.getData().pipe( // rxjs operators );


    ngOnInit() {
       // Subscribe here or anywhere else to your observables
       this.latestReadings$.subscribe(latestReadings => // number of latest readings)
    }


}

重要的部分是使用RXJS转换或合并运算符,以便您可以创建将服务的可观察值作为输入的新可观察值,然后将其通过管道传递,从而创建自己的服务。

RXJS Operators

答案 2 :(得分:0)

我以前是通过以下方式完成此操作的。就像Budhead2004所说的那样,您绝对应该做一些研究,找到适合您需要的良好状态管理解决方案。我自己稍微采用了这种方法,但是对于较小的应用程序或代码段,它可以完成工作。

下面是一个正在运行的堆栈闪电战:https://stackblitz.com/edit/angular-7gjfgt

store.service.ts 管理数据状态,并将MeasuringPoints的数组映射到每个点的单个可观察对象。

store.service.ts

import { Injectable } from '@angular/core';
import { Subject, BehaviorSubject, Observable, from } from 'rxjs';
import { mergeMap, tap } from 'rxjs/operators'
import { MeasuringPoint } from './measuring-point';

const STUB_DATA: MeasuringPoint[] = [
  { data: 'fake data 1' },
  { data: 'fake data 2' },
  { data: 'fake data 3' },
];

@Injectable({ providedIn: 'root' })
export class StoreService {

  // If you receive the data as an array, you will want to store it as an array
  private _subject: Subject<MeasuringPoint[]> = new BehaviorSubject([]);

  // Simple state management. Could switch this out for
  //  a caching library or NGRX
  private loadedData: boolean = false;

  constructor(/* inject needed services (ie. http, etc) */) { }

  // Return single MeasuringPoint objects
  public getAllMeasuringPoints$(): Observable<MeasuringPoint> {
    // If you haven't loaded the data yet, load it now
    if (!this.loadedData) {
      this._subject.next(STUB_DATA);
      this.loadedData = true;
    }

    return this._subject
      // return the observable and not the subject
      .asObservable()
      // Convert the array of MeasuringPoints to emit for each
      //  value in the array
      .pipe(
        // Log values for demonstration
        tap((values: MeasuringPoint[]) => console.log('Values before mapping: ', values)),
        // convert an observable of an array to individual observables
        mergeMap((points: MeasuringPoint[]) => from(points)),
        // Log values for demonstration
        tap((value: MeasuringPoint) => console.log('Values after mapping: ', value)),
      );
  }
}

然后您可以订阅公开的方法来获取数据。任何组件都可以订阅它。由于它是BehaviorSubject,因此订户将始终获得最新的发射值。关于BehaviorSubject的另一点要注意的是,由于 store.service 中的可观察对象从未完成,因此您的组件在销毁后将需要取消订阅。否则,您将在整个应用程序中发生内存泄漏。

first-component.component.ts -注意: second-component.component.ts 几乎是此重复 < / p>

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { StoreService } from './store.service';
import { takeUntil } from 'rxjs/operators';
import { MeasuringPoint } from './measuring-point';

@Component({
  selector: 'app-first-component',
  template: `
    <h3>First Component</h3>
    <div *ngFor="let point of measuringPoints">
      {{point | json}}
    </div>
  `
})
export class FirstComponentComponent implements OnInit, OnDestroy {

  public measuringPoints: MeasuringPoint[] = [];
  // Keep track of subscriptions
  private _endSubscriptions: Subject<null> = new Subject();

  constructor(private _storeService: StoreService) { }

  ngOnInit() {
    this._storeService.getAllMeasuringPoints$()
    // This is to avoid memory leaks by unsubscribing when your component destroys
    .pipe(takeUntil(this._endSubscriptions))
    .subscribe((point: MeasuringPoint) => this.measuringPoints.push(point));
  }

  ngOnDestroy() {
    this._endSubscriptions.next();
    this._endSubscriptions.complete();
  }

}

以下是RxJS from()https://www.learnrxjs.io/operators/creation/from.html

的文档

这应该给您想要的结果。让我知道是否可以。干杯!