2016-10-24 70 views
1

我正在嘗試爲使用angular 2和chart.js(通過ngcharts)的圖表構建一個儀表板。我想有一個圖表陣列,每個圖表通過自定義時間間隔內的http請求進行更新。如何使用interval更新observables數組?

現在我有三個單獨的圖表調用,將數據推送到一個數組。我在遇到下一次迭代時遇到了麻煩 - 如果再次推入陣列,我最終會得到3個圖表。我希望陣列中的訂閱者在間隔發出時使用新數據進行更新。

對於如何正確構造我的用例的組件/服務/ http關係,我有點困惑。我覺得我很接近,但我肯定錯過了一些東西。如何獲取間隔/訂戶關係以映射到視圖並在一個時間間隔內更新現有圖表? 任何幫助將是偉大的!

現在:

服務:

我在這裏實施的時間間隔:

getSingleChartObsinterval(id: number, interval: number) : Observable<Graph> { 

return Observable.interval(interval).flatMap(() => this.getSingleChartobs(id));   
} 


getSingleChartobs(id: number) : Observable<Graph> { 

    return this.jsonp.get(「api location」) 
      .map(response => this.extractJsonData(response, id) as Graph) 
} 

extractJsonData只是採取響應和操縱它與圖表JS工作。它返回一個Graph對象,該對象具有易於使用的屬性。我無法控制API,因此我無法重新配置響應以包含多個圖。

組件:

import { Component } from '@angular/core'; 
import { ChartsModule } from 'ng2-charts/ng2-charts'; 
import { ChartService } from './chart.service'; 
import { Graph } from './graph'; 
import { OnInit } from '@angular/core'; 
import { Observable } from 'rxjs/Rx'; 


@Component({ 
    selector: 'ab-chart', 
    styles: [` 
    .chart { 
     display: block; 
    } 
    `], 
    templateUrl: 'app/chart.component.html' 
}) 
export class ChartComponent implements OnInit { 

    ngOnInit(): void { 
     console.log("Chart component init"); 

     this.getSingleChart(3, 5000); 
     this.getSingleChart(5, 4000); 
     this.getSingleChart(6, 5000); 
    } 

    graph: Graph; 
    graphs: Graph[] = []; 


    constructor(
     private chartService: ChartService 
    ) {} 


    getSingleChart(id: number, interval: number): void { 
    this.chartService.getSingleChartObsinterval(id, interval) 
     .subscribe(x => 
     this.graphs.push(x) 
    ); 
} 
} 

的觀點:

<div *ngFor="let graph of graphs" class="chart-container"> 
    <base-chart 
     class="chart" 
     [datasets]="graph.datasets" 
     [labels]="graph.labels" 
     [options]="graph.options" 
     [chartType]="graph.type"> 
     </base-chart> 
    </div> 
+0

而不是推新圖表在你的數組中,你不能只用新的數據替換現有的圖表嗎?我對chart.js一無所知,所以也許不可能替換他的數據,只是等待角度來渲染新圖表 –

+0

@ NoémiSalaün我認爲這是我問的問題。每張圖表都在不同的時間間隔,所以我希望我可以讓每件物品n陣列訂閱更改和更新自己而不必吹散陣列。我嘗試將每個對象作爲數組的訂閱者,但它沒有奏效。我希望有一種方法可以做到這一點,而無需在陣列中搜索ID並自己更新數據。 – Skerrvy

回答

1

由於每個圖都有自己id(我假設它是唯一的),所以我只希望改變getSingleChart()方法在特定鍵上更新graphs對象。請注意,我改變了graphs屬性從一個數組對象:

graphs: {[key: number]: Graph} = {}; 

getSingleChart(id: number, interval: number): void { 
    this.chartService.getSingleChartObsinterval(id, interval) 
    .subscribe(x => this.graphs[id] = x); 
} 

get graphIds() { 
    return Object.keys(this.graphs); 
} 

然後在你需要遍歷鍵陣列模板(可以迭代graphs對象:

<div *ngFor="let id of graphIds" class="chart-container"> 
    <base-chart 
     class="chart" 
     [datasets]="graphs[id].datasets" 
     [labels]="graphs[id].labels" 
     [options]="graphs[id].options" 
     [chartType]="graphs[id].type"> 
    </base-chart> 
</div> 
+0

感謝您的回答。這兩個答案都奏效了,但這更接近我一直在嘗試的方式,並對我現有的方法造成了最少的變化。 – Skerrvy

1

你有圖表的數量有限?如果你總是有三個,你可以利用combineLatest運算符(如果你有更多的話,你將不得不使用某種形式的遞歸,我猜)。

在你的組件,你可以做到以下幾點:

this.graphs = this.getSingleChart(3, 5000).combineLatest(
     this.getSingleChart(5, 4000), 
     this.getSingleChart(6, 5000), 
     (val1, val2, val3) => return [val1, val2, val3]) 
     //.subscribe((arrayOfVal) => console.log(arrayOfVal); 

這將每一個圖表中獲取更新時間返回一個新的數組。如果圖2得到一個新值,函數(combineLatest的第三個參數)將被調用,舊值爲1,新值爲2,舊值爲3。

在模板你可以只使用此:

<div *ngFor="let graph of graphs | async" ...> 

CombineLatest:https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/combinelatest.md

+0

實際上這不會像這樣工作,因爲'combineLatest()'返回一個Observable,而不是從回調中返回的值。這也意味着你必須一次刷新所有的圖表。 – martin

+0

它確實會返回一個可觀察的。但是,這就是關鍵,在這種情況下,可以在異步管道中使用observable。 combineLatest將不會強制每個圖表進行重新編譯。在封面之下,這將保持所有三個電話的最新價值。例如,A1,B1和C1。如果B1更新到B2,則下一個值將是A1,B2,C1。看到A和C引用沒有改變。所以,它和你的答案一樣。但更優雅的AFAIAC,因爲你不需要清理訂閱後。 – KwintenP

+0

你對'異步'我是沒有注意到的。但是,它必須一次更新所有圖表,而不是像你所描述的那樣更新圖表,因爲每次更改'圖表| async'接收到一個新的數組,然後它會再次破壞並重新創建所有三個元素的''元素。但是你的解決方案肯定比我的更容易。 – martin