2
votes

I am trying to call two observables, with the response from second I manipulate the first and then return a new observable.

return this.http.get(requestUrl)
            .map((response: User) => {
                sessionManager.currentUser = response;
                return this.isFirstTimeUser(response.id);
            })
            .do((response: any) => {
                console.log(response);
                sessionManager.currentUser.firstTimeLogin = response === 'true';
                return Observable.create(sessionManager.currentUser);
            })
            .toPromise();

isFirstTimeUser(response.id) is another function that returns an observable.

private isFirstTimeUser(userId: number): Observable<any> {
        const requestUrl = 'someUrl';
        return this.http.get(requestUrl, {responseType: 'text'});
    }

All I want to do is get the user object from the first http call, make another request using the user's id in the second call and then after I get back the response from the second observable, I update a property of the first response and return the updated first response. How do I achieve this? What rxjs function should I be looking at?

3
In your example, where are you calling a second observable? - Reactgular
isFirstTimeUser(response.id) returns another http Observable. - Anjil Dhamala
checkout my updated answer - Fartab
Can you explain better what you are trying to do? I tried to come up with the answer, but your description is not clear. - codeepic
@codeepic Does the edit help? - Anjil Dhamala

3 Answers

1
votes

You were close in your example.

You want to use switchMap which unsubscribes to the incoming observable, and subscribes to the next observable.

return this.http.get(requestUrl)
        .switchMap((response: User) => {
            sessionManager.currentUser = response;
            return this.isFirstTimeUser(response.id);
        })
        .map((response: any) => {
            console.log(response);
            sessionManager.currentUser.firstTimeLogin = response === 'true';
            return sessionManager.currentUser;
        })
        .toPromise();

The response will be passed to isFirstTimeuser() and the following .map() will be applied to the observabled returned by that function.

It's called switchMap because the observable returned by this.http.get() is unsubscribed and the next observable is used. This won't be a problem with this.http.get(), but keep in mind that switchMap only works for the first emitted value.

2
votes

The solution you're looking for is something like that:

getUser(): Observable<any>{
    return this.http.get(reqUrl)
        .do((res: User) => {
            sessionManager.currentUser = res;
        })
        .switchMap((res: User) => {
            return this.isFirstTimeUser(res.id);
        })
        .do((res: any) => {
            console.log(response);
        }
        .map((res: any) => {
            sessionManager.currentUser.firstTimeLogin = res === 'true';
            return sessionManager.currentUser;
        });
}

Then you just need to subscribe to getUser() and you should be alright. It is still not the best code according to rxjs functional paradigm of pure functions. I guess using concatMap with projection function would get us closer to ideal, but it will work.

The reason it's not ideal is because there's a required side effect in the first .do() block, we update the sessionManager value - a variable outside the function (a big no no in functional world) and then we access it again in .map() function. concatMap with projection function as a 2nd argument would get us around this.

0
votes

Use mergeMap

return this.http.get(requestUrl)
            .mergeMap((response: User) => {
                const currentUser = response;
                currentUser.firstTimeLogin = this.isFirstTimeUser(response.id) === 'true' 
                return Observable.of(currentUser);
            })