Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make nested Observable calls in Angular2

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.

like image 514
nuvio Avatar asked Nov 24 '16 13:11

nuvio


1 Answers

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); } 

legacy:

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); } 
like image 89
j2L4e Avatar answered Sep 28 '22 02:09

j2L4e