按顺序订阅Angular 2+中可变数量的Observable

时间:2018-01-18 17:36:22

标签: javascript angular typescript rxjs observable

很抱歉,如果在其他地方得到解答,我试图搜索,但我甚至不确定我在寻找什么。

假设我有这个对象可以使用:

userRequest: {
    id: number,
    subject: string,
    ...
    orderIds: number[]
    ...
}

order: {
    id: number,
    ...
    clientId: number,
    productIds: number[]
}

client: {
    id: number,
    name: string,
    ...
}

product: {
    id: number,
    name: string,
    price: number
}

现在,用户将在某个时刻使用该复合对象填充表单并将其发送以进行分析。但在发送之前,首先要进行验证。我无法在表单中进行验证,因为用户只是输入纸上收到的数据。如果数据为"无效",将发送更多信息请求。

因此,我需要验证请求,还需要验证订单,产品和客户端。我被要求出示一个"验证请求"屏幕和每个元素被检查后,"有效"或"无效"屏幕。很简单。

但是现在,我发送http请求并让Observables处理。我试图更多地了解他们和所有可用的操作员以及如何混合他们,但此刻,我完全迷失了。

所以,我首先从服务器获得Observable<userRequest>。然后,一旦我收到了userRequest,我需要从他们的id中获取所有订单,当我得到一个&#34; order&#34;时,我必须得到客户端&amp;他的产品。

所有这些都是异步完成的,但在收到订单之前我无法获得客户端或产品,我需要userRequest来提供订单。此外,当我收到订单时,我需要同时获得客户和产品的同时#34;因为他们都需要相同的订单......?对于最后的结局,对于我得到的每个元素(请求,订单,客户,产品),我需要验证它并等待每个元素说出&#34;请求有效&#34;或不。

所以要恢复:

  1. 我需要获得Observable<userRequest>并验证
  2. 现在,我必须得到Observable<order[]>并验证每个订单
  3. 对于每个订单,我必须1)获得Observable<Client>并验证PLUS 2)获得Observable<Product[]>并验证每个订单
  4. 等待每个观察者完成并检查它是否有效
  5. 步骤1和2需要按顺序执行,但是当步骤2完成时,我需要对步骤2的每个结果执行步骤3.1和3.2。等待。

    我确定它远非明确,我只是希望它足够清楚,以便你们想要实现我们想要的东西。如果您对我有任何提示,请分享! ; )

    修改

    我确实知道需要做些什么。但是当我失去我的酷时,就是当我需要按顺序链接Observable时(因为每个依赖于之前的那个),在不同的点我需要调用验证方法,当涉及到客户端和产品时,都需要它的订单ID。我确实尝试了许多方法,但我完全没有理解这个概念。

    bygrace - 不,我不希望验证被阻止。它应该验证所有内容,因为它会导致对所有缺失或无效部分的请求,并且应该在最后显示。这就是为什么我需要一种方法来知道什么时候完成所有事情,以便我可以检查是否找到了错误。

    请求,订单,客户和产品均来自各自的服务。该服务进行http resquest并返回Observable。所以我需要链接调用(当涉及到Order时,我需要为相同的Order Id获取两个Observable)。

    QuietOran - 这是我尝试过的东西。我知道这太可怕了,但我现在迷路了......

    onValidateRequest(requestId: number) {
    
      this.requestService.getUserRequest$(this.requestId)
        .do(request => {
          this.validateRequest(request);
        })
        .concatMap(request => this.orderService.getOrdersForRequest$(request.id))
        .do(orders => {
          this.validateOrders(orders);
        })
        .concatMap(orders => {
    
          // Now, this is were I'm completely lost
          // I manage to get the request and the orders, but in this block, I need to get the client AND the products
          // and validate each one as I receive it
          // Then return something
    
        })
        .do(() => {
          // when I validate an element, if there's an error, I simple add it in an array. 
          // So when ALL the Observable above are completed, this function simply checks
          // if there's something in it
          this.checkForErrors();
        })
        .subscribe();
    

    }

1 个答案:

答案 0 :(得分:0)

我会给你一些粗略的东西,你可以通过反馈来改进,因为我不清楚你想要的数据的最终形状和所有。希望这能指出你正确的方向。

基本上,如果您希望来自一个observable的数据提供给另一个observable,那么您可以使用switchmap或其中一个堂兄弟。如果您需要输入的值以及结果,那么只需将它们与combineLatest或类似的东西混在一起。

console.clear();
function getUserRequest(requestId) {
  return Rx.Observable.of({ id: 1, subject: 'a', orderIds: [10, 20] })
  	.delay(500).take(1);
}
function getOrdersForRequest(requestId) {
  return Rx.Observable.of([
    { id: 10, clientId: 100, productIds: [ 1000 ] },
    { id: 20, clientId: 200, productIds: [ 1001, 1002 ] }
  ]).delay(200).take(1);
}
function getClientForOrder(orderId) {
  let client;
  switch(orderId) {
    case 10:
      client = { id: 100, name: 'Bob' };
      break;
    case 20:
      client = { id: 200, name: 'Alice' };
      break;
  }
  return Rx.Observable.of(client).delay(200).take(1);
}
function getProductsForOrder(orderId) {
  let products;
  switch(orderId) {
    case 10:
      products = [{ id: 1000, name: 'p1', price: 1 }];
      break;
    case 20:
      products = [
        { id: 1001, name: 'p1', price: 2 },
      	{ id: 1002, name: 'p1', price: 3 }
      ];
      break;
  }
  return Rx.Observable.of(products).delay(200).take(1);
}

Rx.Observable.of(1)
  .switchMap(id => Rx.Observable.combineLatest(
    getUserRequest(id),
    getOrdersForRequest(id)
      .switchMap(orders => Rx.Observable.combineLatest(
          Rx.Observable.of(orders),
          Rx.Observable.combineLatest(...orders.map(o => getClientForOrder(o.id))),
          Rx.Observable.combineLatest(...orders.map(o => getProductsForOrder(o.id)))
        )
      ),
    (userRequest, [orders, clients, products]) =>
        ({ userRequest, orders, clients, products })
  )
).subscribe(x => { console.dir(x); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.min.js"></script>

现在我按类别展平了结果。您可能希望它们嵌套或类似的东西。这只是一个粗略的过程,所以根据需要提供反馈。