1

In my current angular project I have a service that returns Observable<Product[]>. I would like to convert that stream to an array of Observables of single Product. I want to achieve this using pipe operators, without subscribing to the original stream.

From Observable of <entity[]> to array of Observables of entity

Narasimhan
  • 73
  • 1
  • 7
  • I don't think this is possible with pipe operators because the pipe method only accept operators that generate one observable. Maybe you can do it by creating an array of BehaviorSubjects and pushing the results there. – ShamPooSham Jun 27 '20 at 10:12
  • Thanks @ShamPooSham. I will try that. – Narasimhan Jun 28 '20 at 13:50
  • Honestly I'm not sure what you want to accomplish with this. From your other comment it looks like you want to loop through the result in your template with `*ngFor` and `async`. This isn't impossible to acheive with `Observable`. Maybe your question should be about that instead – ShamPooSham Jun 28 '20 at 16:34
  • I feel like my solution is quite an ugly one and makes the code harder to reason about. – ShamPooSham Jun 28 '20 at 16:36
  • If am looping over simple div then this would not be required. Actually the component I am looping with *ngFor is expecting an observable of single entity. . – Narasimhan Jun 28 '20 at 18:54

1 Answers1

3

When you're using pipe on an observable, you'll always get back a new observable, never an array. You can access the Product[] and map it to an (Observable<Product>)[] without any problem, but the result will still be wrapped in another observable:

import { of } from 'rxjs';
import { map } from 'rxjs/operators';

interface Product {
    id: number;
}

const products: Observable<Product[]> = of([
    { id: 1 },
    { id: 2 },
    { id: 3 },
]);

products
    .pipe(map(ps => ps.map((p) => of(p))))
    .subscribe((observables: Observable<Product>[]) => {
        // In here you can access the array of observables:
        console.log(observables);
    })

Instead of subscribing to the observable, you could also tap within pipe to access the result of map(), but the result will still only be accessible from within an Observable context:

// ...
import { map, tap } from 'rxjs/operators';
// ...

const x = products
    .pipe(
        map(ps => ps.map((p) => of(p))),
        tap((observables: Observable<Product>[]) => {
            // In here you can also access the array of observables:
            console.log(observables);
        }),
    );

But x is still an observable:

const x: Observable<Observable<Product>[]>

or equivalently but maybe slightly more understandable:

const x: Observable<Array<Observable<Product>>>
JJWesterkamp
  • 7,559
  • 1
  • 22
  • 28
  • One thing that could help understanding is that it's not known in the context of observables how many entries the event array has. An array is not limited and can therefore not be dynamically split into multiple variables. Pairwise is doing what he wants but the operator splits only into two separate parts. – Jonathan Stellwag Jun 27 '20 at 12:58
  • Thanks Jeffrey, that makes lot of sense. But it is not be possible to loop over an observable of observables in the template using async pipe. – Narasimhan Jun 28 '20 at 13:48