Search code examples
angularrxjsobservablengrxngrx-store

How to pass Observable @Input to angular component store?


I'm trying to pass an Observable array into an inner 'dumb' component, do some filtering/mapping on it and then pass it to a custom table object that requires an observable as input. My outer component pipes the observable asynchronously into an @Input with a setter so that the inner component gets it as a regular array. Outer component:

<sales-history
    [salesHistory]="salesHistory$ | async">
</sales-history>

When the @Input loads it updates my component store:

@Input() set salesHistory(val: SalesHistoryLine[]) {
this.store.update({ salesHistory: val });}

This update method is an extension of angular's updater method that updates the state with the provided prop. My store:

export interface SalesHistoryState {
    isLoaded?: boolean;
    salesHistory: SalesHistoryLine[];
    warehousesToShow: number[];
}

@Injectable() export class SalesHistoryStore extends OodleComponentStore<SalesHistoryState> {
    constructor(private whsService: WarehouseService) {
        super({
            salesHistory: [],
            warehousesToShow: []
        });
    }

    salesHistoryWithWhColors$: Observable<SalesHistoryLine[]> = this.select(state => state.salesHistory.filter(value => !! value).map(csh => ({
        ...csh,
        color: this.whsService.whsColorLookup[csh.warehouseId]
      })));

    warehousesToShow$: Observable<number[]> = this.select(state => state.warehousesToShow);

    salesHistory$: Observable<SalesHistoryLine[]> = this.select(
        this.salesHistoryWithWhColors$,
        this.warehousesToShow$,
        (salesHistoryLines, warehousesToShow) => salesHistoryLines.filter(shl =>
        (warehousesToShow ? warehousesToShow.includes(shl.warehouseId) : true)));

    setWarehousesToShow = this.updater((state, warehousesToShow: number[]) => ({
        ...state,
        warehousesToShow
      }));
     }

When I open this dialog component, the sales history does not load the first time I open it, only the second time. What am I doing wrong? I need the salesHistory$ observable to emit to my table object.

ngOnInit:

ngOnInit(): void { 
this.tableBuilder = new TableBuilder(this.store.salesHistory$, meta$)
}

Solution

  • I found my problem. I was selecting one of the observables for the salesHistory$ observable incorrectly. The corrected code is:

    salesHistoryWithWhColors$: Observable<SalesHistoryLine[]> = this.select(state => state.salesHistory).pipe(filter(value => !! value)).pipe(map(csh => csh.map(line => ({
        ...line,
        color: this.whsService.whsColorLookup[line.warehouseId]
      }))));