Francesco
Francesco

Reputation: 10830

Iterate through elements and return Observable of array

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

Answers (1)

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

Related Questions