Reputation: 795
I'm having a problem where I'm returning an observable and sometimes inside that observable I should get a value from another observable. I simplified my problem to much simpler case but main problem is still there. Consider following code that works:
public dummyStream(): Observable<number> {
return of(true).pipe(
switchMap(isTrue =>
iif(() => isTrue === true,
combineLatest([of([1,2,3,4,5]), of(2)]).pipe(
map(([arrayOfNumbers, multiplier]) => {
const results = arrayOfNumbers.map(num => {
if (num !== 5) return num;
else return 4;
});
return results.reduce((prev, curr) => prev + curr, 0);
})
),
combineLatest([of([1,2,3,4,5]), of(2)]).pipe(
map(([arrayOfNumbers, multiplier]) => {
return 0;
})
)
)
)
);
}
So little explanation. It all starts with of(true)
. For simplicity in this example it's always true so once we get to iif()
condition is always true.
Inside there I have combineLatest
that combines two observables. Then eventually I do arrayOfNumbers.map
and simply return that number again except in a case where number is 5 then I return 4.
Now what I'd like to do is to return of(num * multiplier)
but then of course return type from map
would by either number
or Observable<number>
and that's not working.
So this is same code but instead of returning number I'm returning Observable<number>
in else block
public dummyStream(): Observable<number> {
return of(true).pipe(
switchMap(isTrue =>
iif(() => isTrue === true,
combineLatest([of([1,2,3,4,5]), of(2)]).pipe(
map(([arrayOfNumbers, multiplier]) => {
const results = arrayOfNumbers.map(num => {
if (num !== 5) return num;
else of(num * multiplier);
});
return results.reduce((prev, curr) => prev + curr, 0);
})
),
combineLatest([of([1,2,3,4,5]), of(2)]).pipe(
map(([arrayOfNumbers, multiplier]) => {
return 0;
})
)
)
)
);
}
Now how should I change this so that dummyStream()
return type would still be Observable<number>
but so that inside my else block I'm using another observable?
Upvotes: 0
Views: 769
Reputation: 683
Is this what you need?
const data1$ = of([1, 2, 3, 4, 5]).pipe(concatAll());
// const data1$ = from([1, 2, 3, 4, 5]);
const data2$ = of(2).pipe(repeat());
const source$ = zip(data1$, data2$).pipe(
map(([num, multiplier]) => num !== 5 ? num : num * multiplier),
reduce((prev, curr) => prev + curr, 0),
);
source$.subscribe(console.log);
const falseResult$ = of(0);
iif(() => true, source$, falseResult$).subscribe(console.log);
Upvotes: 0
Reputation: 23905
I would restructure dummyStream
like this:
function dummyStream() {
return of(true).pipe(
switchMap(isTrue =>
iif(() => isTrue === true,
combineLatest([of([1,2,3,4,5]), of(2)]).pipe(
switchMap(([arrayOfNumbers, multiplier]) => {
return forkJoin(arrayOfNumbers.map(num => {
if (num !== 5) return of(num);
else return of(num * multiplier);
}));
}),
map((results) => results.reduce((prev, curr) => prev + curr, 0))
),
combineLatest([of([1,2,3,4,5]), of(2)]).pipe(
map(([arrayOfNumbers, multiplier]) => {
return 0;
})
)
)
)
);
}
So instead of just return num
in the map, you return of(num)
so that you end up with an array of Observable<number>
. Change the outer map
to a switchMap
and wrap the resulting array in a forkJoin
to wait for all inner observables to finish. You can put the reduce
in its own map
afterwards.
Upvotes: 2