2017-09-06 30 views
0

我已經建立了一個「全球性」的服務,分享我的角度應用跨組件參數方法:角度:當調用多種簽約(BehaviorSubjects)都被定義

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(); 
     }); 
    } 

param1param2和通過AppComponent,異步初始化,所以部件訂閱兩者參數將以任意順序「通知」(接收值)。每當任一參數改變時,getDataFromAPI應該會獲得新數據,因此這兩個訂閱都會調用該方法,但其他參數仍可能爲undefined

顯然,這可以很容易地通過簡單地檢查是否調用getDataFromAPI之前定義的其他參數,但我想知道什麼是處理這個(當然是常見的)場景的最佳方式? 我應該使用承諾還是等待以確保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); 
    } 
} 
+0

也許你應該使用Observable.forkJoin,它會等待直到所有的觀察對象完成並且發出每個觀測對象的最後一個值。 –

+0

顯然,在簡單的解決方案中,組件不會知道*哪個*參數實際發生了變化,但在我的(特定)情況下,我將在每次進行一個或多個更改時使用所有參數調用API(刷新數據)。所以,它應該適用於我的情況,但也許這種方法太鬆懈。 – joakimk

+0

我想你可以添加if子句'if(this.param2){this.getDataFromAPI(this.param1,this.param2); }到第一個訂閱和'if(this.param1){this.getDataFromAPI(this.param1,this.param2); '到第二個。這將確保只有在定義了兩個參數的情況下,getDataFromApi纔會被執行。 OFC每當他們其中一人發生變化,它將執行所需的更新 –

回答

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

+0

謝謝,按我想要的方式工作! – joakimk