I am having some troubles making nested Observable calls. By that I mean a call to a http service that retrieve a user, then getting the id from the user to make another http call, and finally render the results on screen.
1) HTTP GET 1 : get the User
2) HTTP GET 2: get the User's preferences passing a unique identifier as a parameter
This translates into the following code in component Blah.ts
:
version 1 - this code does not display anything
ngOnInit() { this.userService.getUser() .flatMap(u => { this.user = u; // save the user return Observable.of(u); // pass on the Observable }) .flatMap(u => this.userService.getPreferences(this.user.username)) // get the preferences for this user .map(p => { this.preferences = p; // save the preferences }); }
version 2 - this code works but seems the wrong approach to me:
this.userService.getUser().subscribe(u => { this.user = u; this.userService.getPreferences(this.user.username).subscribe(prefs => { this.preferences = prefs; }); });
And this is the template:
<h3>User</h3> <div class="row col-md-12"> <div class="col-md-6"> <div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">User details</h3> </div> <div class="panel-body"> <table class="table table-condensed"> <thead> <tr> <th>Username</th> <th>Full Name</th> <th>Enabled</th> </tr> </thead> <tbody> <tr> <td>{{user?.username}}</td> <td>{{user?.fullName}}</td> <td>{{user?.enabled}}</td> </tr> </tbody> </table> </div> </div> </div> <!-- end of col 1--> <div class="col-md-6"> <div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">User preferences</h3> </div> <div class="panel-body"> <table class="table table-condensed"> <thead> <tr> <th>Language</th> <th>Locale</th> </tr> </thead> <tbody> <tr> <td>{{preferences?.preferences?.get('language')}}</td> <td>{{preferences?.preferences?.get('locale')}}</td> </tr> </tbody> </table> </div> </div> </div> <!-- end of col 2--> </div> <!-- end of row 1-->
I don't think there is any point in showing the service, which simply makes http get()
calls like:
http.get('http://blablah/users/') .map((response) => response.json())
Please suggest which is the best working approach to define a chain of Observables.
You should read up on rxjs's operators a little. Your examples are very verbose and use flatMap
and map
in a way they're not supposed to be used. Also your first example can't work, because you're not subscribing to the Observable.
This will do what you need:
ngOnInit() { this.userService.getUser().pipe( tap(u => this.user = u), flatMap(u => this.userService.getPreferences(u.username)) ).subscribe(p => this.preferences = p); }
Before version 5.5 rxjs exclusively used prototype-based operators. This code is functionally equivalent to the above:
ngOnInit() { this.userService.getUser() .do(u => this.user = u) //.do just invokes the function. does not manipulate the stream, return value is ignored. .flatMap(u => this.userService.getPreferences(u.username)) .subscribe(p => this.preferences = p); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With