Angular:当多个订阅(BehaviorSubjects)全部定义时调用方法

时间:2017-09-06 08:30:20

标签: angular angular2-services behaviorsubject

我已经设置了一个“全局”服务,以便在我的Angular应用中分享各个组件的参数:

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

@Injectable()
export class ParameterService {

  param1 = new BehaviorSubject(null);
  publishParam1(data: number) {
    this.param1.next(data);
  }

  param2 = new BehaviorSubject(null);
  publishParam2(data: number) {
    this.param2.next(data);
  }

}

需要这些参数中的一个或两个的组件可以订阅,并在这些更改时得到通知:

  private subscriptions: Array<Subscription> = [];
  param1: number; // keep local copies of the params
  param2: number;

  ngOnInit(): void {

    this.subscriptions.push(this._parameterService.param1.subscribe(
      data => {
          console.log("param1 changed: " + data);
          if (data != null) {
            this.param1 = data;
            // NB! this.param2 may be undefined!
            this.getDataFromAPI(this.param1, this.param2);
        }
      }
    ));

    this.subscriptions.push(this._parameterService.param2.subscribe(
      data => {
          console.log("param2 changed: " + data);
          if (data != null) {
            this.param2 = data;
            // NB! this.param1 may be undefined!
            this.getDataFromAPI(this.param1, this.param2);
        }
      }
    ));
  }

  ngOnDestroy() {
    // https://stackoverflow.com/questions/34442693/how-to-cancel-a-subscription-in-angular2
    this.subscriptions.forEach((subscription: Subscription) => {
            subscription.unsubscribe();
        });
  }

param1param2AppComponent异步初始化,因此订阅两个参数的组件将被“通知”(接收值)任意顺序。每当任一参数发生更改时,getDataFromAPI都应获取新数据,因此两个订阅都会调用该方法,但另一个参数可能仍为undefined

显然,通过在调用getDataFromAPI之前简单地检查是否定义了其他参数,可以很容易地解决这个问题,但我想知道处理这个(肯定是常见的)场景的最佳方法是什么? 我应该使用promises还是等待确保仅在定义了两个(所有)参数时调用getDataFromAPI

我想到的一个简单想法是确保ParameterService只包含一个参数;即在某个“州级”中包裹param1param2

export class StateObject {
    param1: number;
    param2: number;

    constructor() { }
}

使ParameterService成为,

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { StateObject } from './stateobject';

@Injectable()
export class ParameterService {

  state = new BehaviorSubject(null);
  publishState(data: StateObject) {
    this.state.next(data);
  }
}

1 个答案:

答案 0 :(得分:1)

你可以尝试:

let subscription  = Rx.Observable.combineLatest(
    this._parameterService.param1,
    this._parameterService.param2
  )
  .subscribe(data => {
      console.log("param1 or param2 changed: " + data);
      let [p1, p2] = data;
      this.getDataFromAPI(this.param1 = p1, this.param2 = p1);
    })
);

或使用投影功能:

let subscription  = Rx.Observable.combineLatest(
    this._parameterService.param1,
    this._parameterService.param2,
    (p1, p2) => { p1: p1, p2: p2 }
  )
  .subscribe(data => {
      console.log("param1 or param2 changed: " + data);
      this.getDataFromAPI(this.param1 = data.p1, this.param2 = data.p2);
    })
);

combineLatest API reference