如何使用interval更新一个observable数组?

时间:2021-12-10 21:19:02

I’m trying to build a dashboard for charts using angular 2 and chart.js (via ngcharts). I’d like to have an array of charts that each update via an http request on a custom interval.

我正在尝试使用angular 2和chart.js(通过ngcharts)为图表构建仪表板。我想要一个图表数组,每个图表都通过自定义间隔的http请求进行更新。

Right now I have three separate chart calls that push data to an array. I’m having trouble when it comes to the next iteration - if I push to the array again, I’ll end up with 3 more charts. I’d like the subscribers in the array to update with new data when the interval emits it.

现在我有三个单独的图表调用,将数据推送到数组。我在下一次迭代时遇到了麻烦 - 如果我再次推送到阵列,我最终会再增加3个图表。我希望数组中的订阅者在间隔发出时使用新数据进行更新。

I’m a little confused as to how to correctly structure the component/service/http relationship for my use case. I feel that I’m close but I’m definitely missing something. How can I get the interval/subscriber relationship to map to the view and update the existing charts on an interval? Any help would be great!

关于如何为我的用例正确构建组件/服务/ http关系,我有点困惑。我觉得我很亲密,但我肯定错过了一些东西。如何让间隔/订户关系映射到视图并在一定时间间隔内更新现有图表?任何帮助都会很棒!

Right now:

Service:

I’m implementing the interval here:

我在这里实施间隔:

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 is just taking the response and manipulating it to work with the chart JS. It returns a Graph object that has properties that are easy to work with. I don’t have control of the API so I can’t reconfigure the response to include more than one graph.

extractJsonData只是接受响应并操纵它来使用图表JS。它返回一个Graph对象,该对象具有易于使用的属性。我无法控制API,因此我无法重新配置响应以包含多个图表。

The component:

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

The view:

<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>

2 个解决方案

#1


1  

Since each graph has its own id (I assume its unique) so I'd just change getSingleChart() method to update graphs object at specific key. Note I changed the graphs property from an array to an object:

由于每个图都有自己的id(我假设它是唯一的)所以我只需更改getSingleChart()方法来更新特定键的图形对象。注意我将graph属性从数组更改为对象:

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

Then in the template you need to iterate the array of keys (you can iterate the graphs object:

然后在模板中,您需要迭代键数组(您可以迭代图形对象:

<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>

#2


1  

Do you have a limited amount of charts? If you always have three you could leverage the combineLatest operator (if you have more you would have to use some form of recursion I guess).

你的图表数量有限吗?如果你总是有三个你可以利用combineLatest运算符(如果你有更多,你必须使用某种形式的递归我猜)。

In your component you could do the following:

在您的组件中,您可以执行以下操作:

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

This will return a new array every time one of the charts gets updated. If chart 2 gets a new value, the function (third argument of the combineLatest) will be called with the old value of 1, the new value for 2 and the old value of three.

每次更新其中一个图表时,这将返回一个新数组。如果图表2获得一个新值,则将使用旧值1,新值2和旧值3调用函数(combineLatest的第三个参数)。

In your template you could just be using this:

在您的模板中,您可以使用此:

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

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

#1


1  

Since each graph has its own id (I assume its unique) so I'd just change getSingleChart() method to update graphs object at specific key. Note I changed the graphs property from an array to an object:

由于每个图都有自己的id(我假设它是唯一的)所以我只需更改getSingleChart()方法来更新特定键的图形对象。注意我将graph属性从数组更改为对象:

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

Then in the template you need to iterate the array of keys (you can iterate the graphs object:

然后在模板中,您需要迭代键数组(您可以迭代图形对象:

<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>

#2


1  

Do you have a limited amount of charts? If you always have three you could leverage the combineLatest operator (if you have more you would have to use some form of recursion I guess).

你的图表数量有限吗?如果你总是有三个你可以利用combineLatest运算符(如果你有更多,你必须使用某种形式的递归我猜)。

In your component you could do the following:

在您的组件中,您可以执行以下操作:

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

This will return a new array every time one of the charts gets updated. If chart 2 gets a new value, the function (third argument of the combineLatest) will be called with the old value of 1, the new value for 2 and the old value of three.

每次更新其中一个图表时,这将返回一个新数组。如果图表2获得一个新值,则将使用旧值1,新值2和旧值3调用函数(combineLatest的第三个参数)。

In your template you could just be using this:

在您的模板中,您可以使用此:

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

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