2016-11-24 99 views
11

我遇到了一些麻煩,使得嵌套的Observable調用。我的意思是調用一個http服務來檢索一個用戶,然後從用戶那裏獲取id來進行另一個http調用,最後在屏幕上顯示結果。如何在Angular2中嵌套Observable調用

1)HTTP GET 1:獲得用戶

2)HTTP GET 2:獲取用戶的偏好通過一個唯一的標識符作爲一個參數

這轉化爲下面的代碼在組分Blah.ts

版本1 - 這個代碼不顯示任何內容

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

版本2 - 此代碼的工作,但似乎錯誤的做法對我說:

this.userService.getUser().subscribe(u => { 
      this.user = u; 
      this.userService.getPreferences(this.user.username).subscribe(prefs => { 
       this.preferences = prefs; 
      }); 
     }); 

這是模板:

<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--> 

我不認爲這是在展示該服務的任何點,這只是使http get()調用,如:

http.get('http://blablah/users/') 
     .map((response) => response.json()) 

請建議其最好的工作方法定義一個Observable鏈。

+0

「這段代碼的作品,但似乎是錯誤的做法,我...」爲什麼? –

回答

14

您應該rxjs的運營商一點點讀了。您的示例非常冗長,並且使用flatMapmap以不應使用它們的方式。你的第一個例子也無法工作,因爲你沒有訂閱Observable。

這將你需要的東西:

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

+1 - 我只有一個問題,使用這個解決方案,處理任何服務調用可能拋出的錯誤的最佳方法是什麼?我明白你可以在subscribe方法中添加一個錯誤處理程序;但是,這隻適用於getPreferences服務調用。在一個點上捕獲錯誤的最簡單方法是什麼?假設它們都應該以相同的方式處理。謝謝 – Sam

+2

任何錯誤將通過管道一路向下 – j2L4e

+1

感謝澄清!現在我更好地理解這是如何工作的,謝謝。 – Sam

2

你是正確的,嵌套的訂閱是錯誤的...

flatmap是正確的

這應該有助於

https://embed.plnkr.co/mqR9jE/preview

或閱讀本教程

https://gist.github.com/staltz/868e7e9bc2a7b8c1f754

一些代碼...

// responseStream: stream of JSON responses 
var responseStream = requestStream 
    // We use flatMap instead of map to prevent this stream being a metastream - i.e. stream of streams 
    .flatMap(requestUrl => { 
    // Convert promise to stream 
    return Rx.Observable.fromPromise($.getJSON(requestUrl)); 
    }).publish().refCount(); // Make responseStream a hot observable, prevents multiple API requests 
// see https://gist.github.com/staltz/868e7e9bc2a7b8c1f754#gistcomment-1255116 

這裏請求URL是從一個不同的流/可觀察發出的輸入。

現在訂閱responseStream

1

版本1是最好的,應該的作品,你忘記了訂閱:

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 
     }) 
     .subscribe(); 
} 
2

好了,所以從這裏上網掙扎和整理信息的後一天是我所學到的有關鏈接觀測量(在順序調用觀測量 - 一個又一個):

我正在使用一個Angular2(4)網站,並且此站點使用java後端API來獲取/設置/修改數據庫中的信息。

我的問題是,我必須在返回Observables(RxJS)的序列中做兩個API(HTTP POST)調用。

我有Operation1和Operation2。操作2應在操作完成後執行1。 enter image description here

VARIANT1 - >起初,我做了一個內部的其他(在JavaScript像嵌套函數):

 this.someService.operation1(someParameters).subscribe(
     resFromOp1 => { 
      this.someService.operation2(otherParameters).subscribe(
      resFromOp2 => { 
       // After the two operations are done with success 
       this.refreshPageMyFunction() 
      }, 
      errFromOp2 => { 
       console.log(errFromOp2); 
      } 
     ); 
     }, 
     errFromOp1 => { 
      console.log(errFromOp1); 
     } 
    ); 

儘管這個代碼是合法和工作,我有要求,鏈這些觀測量一個後另一個類似於Promise的異步函數。一種方法是將Observables轉換爲Promises。

Onother方法是使用RxJS flatMap:

VARIANT2 - >另一種方法是用flatMap做到這一點,其作爲我理解類似於承諾然後:

this.someService.operation1(someParameters) 
    .flatMap(u => this.someService.operation2(otherParameters)) 
    .subscribe(function(){ 
     return this.refreshPageMyFunction() 
     }, 
     function (error) { 
     console.log(error); 
     } 
    ); 

VARIANT3 - >用相同的箭功能:

this.someService.operation1(someParameters) 
    .flatMap(() => this.someService.operation2(otherParameters)) 
    .subscribe(() => this.refreshPageMyFunction(), 
     error => console.log(error) 
    ); 

這回觀測量的方法基本上都是這些:

operation1(someParameters): Observable<any> { 
    return this.http.post('api/foo/bar', someParameters); 
    } 

    operation2(otherParameters): Observable<any> { 
    return this.http.post('api/some/thing', otherParameters); 
    } 

額外的資源和有用的意見:

This post approved answer by @j2L4e: https://stackoverflow.com/a/40803745/2979938 

https://stackoverflow.com/a/34523396/2979938 

https://stackoverflow.com/a/37777382/2979938 
+0

我喜歡這個回覆,但是,大多數異步鏈式的情況涉及到從操作1傳遞參數到操作2,你可能會添加到你的例子而不是其他參數?我完全理解你的例子,但這會使他們完成。 – Undrium