2016-11-24 7 views
11

У меня возникли проблемы с вложенными Наблюдаемыми вызовами. Под этим я подразумеваю вызов службы http, которая извлекает пользователя, затем получает идентификатор от пользователя, чтобы сделать еще один http-вызов, и, наконец, отобразить результаты на экране.Как сделать вложенные Наблюдаемые вызовы в Angular2

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

Пожалуйста, предложите что является лучшим рабочим подходом для определения цепочки наблюдаемых.

+0

«этот код работает, но кажется, неправильный подход ко мне ...» Почему? –

ответ

14

Вы должны прочитать на операторах rxjs немного. Ваши примеры очень подробные и используют flatMap и map так, как они не должны использоваться. Также ваш первый пример не может работать, потому что вы не подписываетесь на 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 - У меня только один вопрос, используя это решение, как лучше всего обрабатывать ошибки, которые могут быть вызваны вызовом службы? Я понимаю, что вы можете добавить обработчик ошибок в метод подписки; однако это применимо только к вызову службы 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), и этот сайт использует API-интерфейс java для получения/установки/изменения информации в базе данных.

Проблема была в том, что мне пришлось выполнять два вызова API (HTTP POST) в последовательности, которая возвращает Observables (RxJS).

У меня есть операция1 и операция2. Операция 2 должна выполняться после завершения работы1. enter image description here

Вариант 1 -> Сначала я сделал это один внутри другого (как вложенные функции в 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); 
     } 
    ); 

Несмотря на этот код легализоваться и работать, у меня было требование к цепи эти Наблюдаемые один за другой, как это делается с асинхронными функциями с обещаниями. Один из способов - преобразовать 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

Мне нравится этот ответ, однако большинство асинхронных цепочечных цепочек включают передачу параметра from operation1 в operation2, не могли бы вы добавить это к вашим примерам вместо otherParameters? Я полностью понимаю ваши примеры, но это сделает их законченными. – Undrium

 Смежные вопросы

  • Нет связанных вопросов^_^