1

I have two different API endpoints. One returns a Cards object, the other an Array of Cards objects. What I want to do is get the first Card as the first element in the Array from the second endpoint. Is there any way to do that? Both are observables returned from HTTPClient, so maybe it would be simple to do with some operator, but I don't know enough to do that yet. Just to illustrate it better:

I have:

latestCards$: Observable<Cards> = http.get('latestCardsEndpoint');
// { title: 'Latest', cards: [], ... }  

featuredCards$: Observable<Cards[]> = http.get('featuredCardsEndpoint');
// [
//   { title: 'Featured1', cards: [], ... }, 
//   { title: 'Featured2', cards: [], ... },
//   ...
// ]

I need

homeCards$: Observable<Cards[]>;
// [
//   { title: 'Latest', cards: [], ... },
//   { title: 'Featured1', cards: [], ... },
//   { title: 'Featured2', cards: [], ... },
//   ...
// ]

2 Answers 2

2

Sure:

Naive approach:

import {forkJoin} from 'rxjs/observable/forkJoin';
import {map} from 'rxjs/operators';

homeCards$= forkJoin(latestCards$,featuredCards$).pipe(
  map(([latest,feature]=>[latest,...feature])
);

This has one limitation: waits for both requests to be completed to emit the first value, which is the complete list.

Naive approach 2:

import {combineLatest} from 'rxjs/observable/combineLatest';
import {map} from 'rxjs/operators';

homeCards$= combineLatest(latestCards$,featuredCards$).pipe(
  map(([latest,feature]=>[latest,...feature])
);

Same limitation as before, only that it waits for both streams to emit at least once. Because these are http observables, they only emit once (response) and then complete. So its the same.

A better approach:

Assuming that the latestCard$ request takes less time to respond, use it as first result while fetching the rest of the data on the background.

import {merge} from 'rxjs/observable/merge';
import {of} from 'rxjs/observable/of';
import {mergeMap, map}from'rxjs/operators';

homeCards$= latestCards$.mergeMap(latest => {
            const fullResult$ = featuredCards$.map(featured => [latest,...featured]);
            return merge(of([latest]), fullResult$);
            });
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. While both the 2 'naive' approaches - and also @Boris's answer - work better for my specific project, your answer was really good and helped me realize some other aspects of working with observables and operators.
2

There are many ways to solve this, one would be this:

Observable
    .combineLatest(latestCards$, featuredCards$) // return an array of responses
    .map(([lastestCard, featuredCards]) => [lastestCard, ...featuredCards])
    .subscribe(// do your stuff)

Here's an example in jsfiddle: http://jsfiddle.net/foxfghhn/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.