Reputation: 83
Is it possible to convert or cast the BehaviorSubject to an array stream? Or pls advise best practice.
data.js
export const ShoppingList = {
id: 22,
username: 'Duff',
groceries: [
{
day: 'Monday',
purchases: [ { item: 'Beer', price: 10 }, { item: 'Pizza', price: 15 } ]
},
{
day: 'Tuesday',
purchases: [ { item: 'Wine', price: 10 }, { item: 'Steak', price: 15 } ]
},
]
}
service.ts
import { Injectable } from '@angular/core';
import { ShoppingList } from './data.js'
//
import { BehaviorSubject } from 'rxjs';
import { pluck } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class DataService {
shopping_list$ = new BehaviorSubject<any>(ShoppingList);
user_name$ = this.shopping_list$.pipe(pluck('username');
id$ = this.shopping_list$.pipe(pluck('id')
**day$ = new BehaviorSubject<[]>(ShoppingList_groceries[0].day);**
**purchases$ = new BehaviorSubject<[]>(ShoppingList_groceries[0].purchases);**
constructor() {}
}
list-component.ts
import { DataService } from '../service/data.service.ts';
//
import { from, Observable } from 'rxjs';
import { tap, map, pluck, reduce, switchMap } from 'rxjs/operators';
@Component({
selector: 'app-list',
templateUrl: './list.component.html',
styleUrls: ['./list.component.css']
})
export class ListComponent implements OnInit {
shopping_list = this.dataService.shopping_list$;
user_name = this.dataService.user_name$;
id = this.dataService.id$;
day = this.dataService.day$
***prices = this.dataService.purchases$.pipe(
pluck('prices'),
reduce((a:number, c:number) => a + c),
tap(y => console.log(y))
);***
constructor(private dataService: DataService) {}
ngOnInit() {
this.shopping_list.subscribe(val => console.log(val))
this.prices.subscribe(val => console.log(val))
}
}
list-component.html
<h1>{{ user_name }} {{ id }} </h1>
<p>{{ day }}</p>
<p>{{ prices }}</p>
is it possible to pipe a BehaviorSubject to work like *from function? Is this best practice or is there a better pattern to build? Any feedback would be much appreciated.
Upvotes: 1
Views: 396
Reputation: 6152
BehaviorSubject
A Subject that requires an initial value and emits its current value to new subscribers
In other words. Think of it like a store rather than a stream of data. You put something in it and once someone subscribes to it now or later will get that value back.
Not possible to cast into an array stream.
One possible approach would be the following:
First collect and summarize all purchases by days.
purchasesByDays$ = new BehaviorSubject<number[]>(
ShoppingList.groceries.map(day => {
return day.purchases.reduce((total, purc) => total + purc.price, 0);
})
);
Once this is done, pipe to this with a simple map in the component.
this.grandTotal$ = this.dataService.purchasesByDays$
.pipe(
map(
(arr: number[]) => {
return arr.reduce((total: number, curr: number) => total + curr, 0);
})
);
Demo Stackblitz.
Upvotes: 1