javascript-从多个HTTP请求加载RxJs / Angular,并从每个请求更新模型

我已经使用Angular / RxJS已有几周了,并且具有根据多个REST请求构建的各种模型,到目前为止,我已经使用switchMap()实现了该模型.这是一个简单的示例(stackblitz:https://stackblitz.com/edit/angular-o1djbb):

import { Component,OnInit,} from '@angular/core';
import { Observable,of } from 'rxjs';
import { delay,switchMap } from 'rxjs/operators';

interface Order {
  id: string;
  itemName: string;
  details?: string;
}

@Component({
  selector: 'my-app',templateUrl: './app.component.html',styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  order: Order;

  ngOnInit() {
    this.getOrderFromApi(123)
      .subscribe(item => this.order = item);
  }

  getOrderFromApi(id): Observable<Order>  {
    const item$= this.getItemName(id);
    const fullItem$= item$.pipe(
      switchMap(n => {
        console.log(`Got name: '${n}''`);
        return this.getDetails(n);
      },(nameReq,detailsReq) => ({ id: '123',itemName: nameReq,details: detailsReq })
      ));
    return fullItem$;
  }

  getItemName(id): Observable<string> {
    return this.fakeXhr('foo');
  }

  getDetails(itemName): Observable<string> {
    console.log(`Got details '${itemName}''`)
    return this.fakeXhr('Some details about foo');
  }

  fakeXhr(payload: any) {
    return of(payload)
      .pipe(delay(2000));
  }
}

和一个简单的模板:

<p>
  item: {{order && order.itemName}}
</p>
<p>
  details: {{order && order.details}}
</p>

这可行,但是直到两个请求都完成,订单信息才会呈现.我想让itemName在可用时立即呈现,然后在可用时呈现细节.因此,利用了Observables可以发出的多个值.例如:

// first value emitted:
{ itemName: 'foo',details: null }
// second value emitted:
{ itemName: 'foo',details: 'Some details about foo' }

我意识到我可能可以通过BehaviourSubject或Redux来实现(就像我过去使用React一样),但是由于所有这些对我来说都是新事物,所以我觉得我没有一个简单的解决方案.

最佳答案
使用expand直接从第一个请求发出数据,然后执行第二个请求.

expand将递归调用内部请求,从上一个请求中获取订单作为输入,因此,我们仅在订单没有详细信息时才执行第二个请求,否则以EMPTY Observable结束递归.

import { Observable,EMPTY } from 'rxjs';
import { map,expand } from 'rxjs/operators';

getOrderFromApi(id): Observable<Order> {
  return this.getItemName(id).pipe(
    map(itemName => ({ id,itemName,details: null } as Order)),expand(order => order.details
      ? EMPTY
      : this.getDetails(order.itemName).pipe(
        map(details => ({ id,itemName: order.itemName,details } as Order))
      )
    )
  );
}

https://stackblitz.com/edit/angular-umqyem

返回的Observable将发出:

> {“ id”:123,“ itemName”:“ foo”,“ details”:null}
> {“ id”:123,“ details”:“有关foo的一些详细信息”}

相关文章

kindeditor4.x代码高亮功能默认使用的是prettify插件,prett...
这一篇我将介绍如何让kindeditor4.x整合SyntaxHighlighter代...
js如何实现弹出form提交表单?(图文+视频)
js怎么获取复选框选中的值
js如何实现倒计时跳转页面
如何用js控制图片放大缩小