Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

handling observables when one is dependent on data from another

When one observable runs it is depedent on data which comes from another obseravble and I can't work out how to hanlde this dependency correctly.

One observable gets data from Firebase and by subscribing it creates a simple number array called novelsRead: Array

The other observable gets a response from an api and by subscribing it is meant to filter out all the records who's ids are present in novelsRead[].

The issue is, when a response comes from the api, novelsRead[] is still empty because Firebase hasn't responded yet so nothing will be filtered from the api response.

Code below:

export class HomePage {

currentnovels: any;
novels: any;
unreadnovels: any;
nextnovels: any;
novel: any;
resultsPageNumber: number = 1;
novelFullPosterPath: any;
novelsread: Array<number> = [];

private basePosterUrlMedium = 'http://image.novels.org/t/p/w500';
private basePosterUrlSmall = 'http://image.novels.org/t/p/w185';

constructor(private http: Http,
    private novelsApi: NovelsApiService,
    private dataService: DataService,
) {
    //this takes data from Firebase and pushes it to simple array of ids (numbers)
    this.dataService.list('novels-read')
        .subscribe(data => {
            data.map(results => {
                this.novelsread.push(results.novelsId);
            })
        })
}


ngAfterViewInit() {
    this.novelsApi.getnovelsByPage(this.resultsPageNumber)
    .subscribe(data => {
        this.novels = data.results;
        this.novels.map(data => {

            data.full_poster_path = this.basePosterUrlMedium + data.poster_path;
            return data;
        })
            .filter(data => {
                let found = this.novelsread.indexOf(data.id);
                //It seems when the api responds, this.novelsRead is still empty [] because Firebase has not responded yet
                console.log("this novelsread[0] is ", this.novelsread[0]);
                console.log("data.id found is ", found);
                return data;
            })
    })
}

I am looking for the cleanest solution whether that's using events, or observable chains or any other suggestions like moving functions from the constructor to ngAfterViewInit and vice versa.

I did look at code examples for combining observables using combineLatest but found the syntax very convoluted and wondered if there is a cleaner way of achiveing what I need, even if that involves waiting for events.

like image 990
Tech 75 Avatar asked Feb 12 '17 14:02

Tech 75


People also ask

Are observables synchronous or asynchronous?

An observable produces values over time. An array is created as a static set of values. In a sense, observables are asynchronous where arrays are synchronous. In the following examples, → implies asynchronous value delivery.

What function must be used with an Observable to handle a data response?

The subscriber function defines how to obtain or generate values or messages to be published. To execute the observable you have created and begin receiving notifications, you call its subscribe() method, passing an observer. This is a JavaScript object that defines the handlers for the notifications you receive.

How are observables asynchronous?

A common misconception in Angular development is regarding whether observables are synchronous or asynchronous. A lot of (even experienced Angular developers) think that observables are async, but the truth is that they can be… Both synchronous and asynchronous.

Why are observables used while fetching data from the API?

Observable is important because it helps to manage asynchronous data (such as data coming from a back-end server). So we can think of Observable as an array where items arrive asynchronously over time. With Observable we need a method in our code that will subscribe to this observable.


1 Answers

Using forkJoin should help you. It allows to handle result only when both requests complete: https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/forkjoin.md

OR if your 2nd request depends on 1st response - use switchMap

const request1$ = Rx.Observable.of('response1').delay(2000);
const request2$ = Rx.Observable.of('response2').delay(100);

Rx.Observable.forkJoin(request1$, request2$)
  .subscribe(res => console.log(`forkJoin: ${res}`));

request1$.switchMap(res1 => {
  console.log(`switchMap: ${res1}`);
  return request2$;
}).subscribe(res2 => console.log(`switchMap: ${res2}`));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.3.0/Rx.min.js"></script>
like image 134
mrkosima Avatar answered Sep 29 '22 06:09

mrkosima