2017-04-08 43 views
0

我有一串数据以Firebase的可观察流的形式进入。即在Angular2中汇总数据流

items: FirebaseListObservable<BucketlistItem[]> = [{ 
    room: 'kitchen', 
    price: 200 
}, { 
    room: 'kitchen', 
    price: 400 
}, { 
    room: 'bedroom', 
    price: 400 
}] 

我想把它变成一个汇总列表,例如加起来类似房间的价格。

[{ 
    room: 'kitchen', 
    price: 600 
}, { 
    room: 'bedroom', 
    price: 400 
}] 

我已经实现了这一点,通过订阅可观察项目并在飞行中将其聚合以在条形图中显示它。但是,这看起来并不像最佳的解决方案,特别是在视图中经常更改items数组。有没有一种聪明的方式来使用observables来获得更强大的解决方案?

import {Component, Input, OnInit, Output, EventEmitter} from '@angular/core'; 
import {BucketlistItem} from "../../bucketlist/bucketlist-item"; 
import {FirebaseListObservable} from "angularfire2"; 

@Component({ 
    selector: 'app-inspiration-header', 
    templateUrl: './inspiration-header.component.html', 
    styleUrls: ['./inspiration-header.component.css'] 
}) 
export class InspirationHeaderComponent implements OnInit, Input { 
    @Input() items: FirebaseListObservable<BucketlistItem[]>; 

    @Input() budget: string; 
    @Output() onBudget = new EventEmitter<string>(); 
    public percentOfBudget: number; 
    public totalCost: number; 

    public barChartLabels: string[] = []; 

    public barChartData: any = 
    [{data: []}] 
    ; 

    constructor() { } 

    ngOnInit() { 
    this.items 
     .subscribe(items => { 
     const aggregate = {}; 
     let totalCost = 0; 
     for (const item of items) { 
      if (item.bucketed) { 
      totalCost += Number(item.price); 
      if (item.room in aggregate) { 
       aggregate[item.room] += Number(item.price); 
      } else { 
       aggregate[item.room] = Number(item.price); 
      } 
      } 
     } 
     this.setPercentageOfBudget(totalCost); 
     this.totalCost = totalCost; 
     for (const room in aggregate) { 
      this.barChartLabels.push(room); 
      this.barChartData[0].data.push(aggregate[room]); 
     } 
     this.barChartLabels = Object.keys(aggregate); 
     }); 
    } 

    private setPercentageOfBudget(totalCost: number) { 
    this.percentOfBudget = Math.round(totalCost/Number(this.budget) * 100); 
    } 

} 
+0

只有当所有数据都可用时才显示图表正确吗? – Aravind

回答

2

根据您所描述的内容,您可能希望使用扫描运算符。

只要扫描运算符的源observable发射一个值,扫描运算符就会发射。但是,扫描运算符的回调将同时接收源观察值发出的当前值以及过去提交中的accumulated value(类似于Array.reduce的工作原理)。

听起来很复杂,但实际上这意味着每当源观察值发出一个值时,扫描运算符会将该新值与“旧值”合并,然后发出新的合并值。

您仍然必须编写逻辑来将新值与旧累计值结合起来,但是我认为由此产生的可观察值将使您更接近您想要的值。

// don't forget to import your operator 
import 'rxjs/add/operator/scan'; 
..... 


    @Input() items: FirebaseListObservable<BucketlistItem[]>; 
    combinedItems: Observable<BucketlistItem[]>; 

    ngOnInit() { 
    this.combinedItems = items.scan((accumulated, current) => { 
     return this.combine(accumulated, current); 
    }); 
    } 

    combine(total: BucketListItem[], newItem: BucketListItem[]) { 
    // implement your similar logic of combining 
    // [{room: 'kitchen', price: 200}] <-- accumulated 
    // with [{room: 'kitchen', price: 200}, {room: 'kitchen', price: 400}] <--- current 
    // to give your final output 
    } 

有没有得到实现组合逻辑(尽管你可以创造性地使用Array.reduce来简化你的代码)。

+0

这是一个非常好的建议 - 谢谢! – user3642173