Reputation: 10830
I have an Observable where User has an array property Posts[] that I want to iterate through, invoke a method with the intermediate values and then return an Observable with the resulting objects as arrays.
At the moment I have the following code that works:
public ngOnInit() {
const results: any[] = [];
this.controlData$ = this.controlContent$
.pipe(
filter((input) => input !== null),
flatMap((p: IControlContentSection) => p.controlPerformers),
map((m: IControlPerformer) => {
results.push({
...m,
nextOccurrence: this.getNextControlDate(m.controlFrequency, m.firstOccurrence),
});
return results;
}),
takeUntil(this.destroy$),
);
}
I use an array variable results: any[]
, but I do not like this solution as it relies on this external variable, making it working only when the component is initialized.
I tried to use toArray()
or a reduce((x, y) => x.concat(y), [])
after the map, but this then resolves into null in the template.
How can I return an Observable without the need of an external variable?
In template I subscribe via async pipe:
<div *ngIf="controlData$ | async as controllers">
...
<div *ngFor="let ctrl of controllers; trackBy:ctrl?.userId">
...
</div>
</div>
Upvotes: 1
Views: 2000
Reputation: 2629
You are doing it correctly after the map, it should work. But to simulate your exact behavior you need a scan operator. The scan operator will emit intermediate values, as you do returning your results array. Have you tried it like this?:
public ngOnInit() {
this.controlData$ = this.controlContent$
.pipe(
filter((input) => input !== null),
flatMap((p: IControlContentSection) => p.controlPerformers),
map((m: IControlPerformer) => {
return {...m,
nextOccurrence: this.getNextControlDate(m.controlFrequency, m.firstOccurrence),
};
}),
scan((acc, cur) => [...acc, cur], [])
takeUntil(this.destroy$),
);
}
It should work, if not, I could provide you a plunker or so.
Hope this helps.
Upvotes: 1