Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

493
Visualizações
RxJs: multiple requests followed by one request via concatMap not working

I make an api call which returns an array. I need to loop over this array and perform a new request per item. The following code works fine:

return this.expeditionService.getTranssmartBookingXml(request).pipe(
  concatMap((response) => {
    return from(response.barcodes).pipe(
      concatMap((barcode) => {
        return this.expeditionService.saveTranssmartBarcode({
          ...saveBarcodeRequest,
          barcode: barcode,
        });
      })
    );
  })
);

However, when all items are finished, I want to make another request. Just one.

But when I use the following code, the process stops when the first item in the from array is finished.

return this.expeditionService.getTranssmartBookingXml(request).pipe(
  concatMap((response) => {
    return from(response.barcodes).pipe(
      concatMap((barcode) => {
        return this.expeditionService.saveTranssmartBarcode({
          ...saveBarcodeRequest,
          barcode: barcode,
        });
      }),
      concatMap(() => {
        const transsmartSaveShipmentRequest: TranssmartSaveShipmentRequest =
          {
            reference: this.shipmentReferenceResult!.reference,
            price: this.transsmartDoBookingResponse!.price,
            trackingUrl: this.transsmartDoBookingResponse!.trackingUrl,
          };

        return this.expeditionService.saveTranssmartShipment(
          transsmartSaveShipmentRequest
        );
      })
    );
  })

I also had some slightly modified code where it was working, but then the final request was executed for each item in the array, where it only needs to execute once.

Does anybody know how to fix this? Thanks in advance!!

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

  1. Piping a higher order operator like concatMap to a stream from from function would trigger it for each element of it's source array. You'd need to use an opeartor like last to restrict the stream only to the last element at a specific point of the stream.

  2. Though it wouldn't make a difference piping last to either inner or outer observable, I'd prefer piping it to outer observable since it looks more elegant.

return this.expeditionService.getTranssmartBookingXml(request).pipe(
  concatMap((response) => {
    return from(response.barcodes).pipe(
      concatMap((barcode) => {
        return this.expeditionService.saveTranssmartBarcode({
          ...saveBarcodeRequest,
          barcode: barcode,
        });
      })
    )
  }),
  last(),
  concatMap(() => {
    const transsmartSaveShipmentRequest: TranssmartSaveShipmentRequest = {
      reference: this.shipmentReferenceResult!.reference,
      price: this.transsmartDoBookingResponse!.price,
      trackingUrl: this.transsmartDoBookingResponse!.trackingUrl,
    };

    return this.expeditionService.saveTranssmartShipment(
      transsmartSaveShipmentRequest
    );
  })
);
over 4 years ago · Santiago Trujillo Relatório

0

You can either use toArray to combine a bunch of separate emissions into a single array, or you can use concat to just process the two observables in serial since you really don't seem to want the results of saving barcodes.

I prefer the second, but both will do want you want and look cleaner than what you have.

ToArray Method

return this.expeditionService.getTranssmartBookingXml(request).pipe(
  concatMap(res => from(res.barcodes)),
  concatMap(barcode => this.expeditionService.saveTranssmartBarcode({
    ...saveBarcodeRequest,
    barcode
  })),
  toArray(),
  concatMap(() => /* save TrannsmartShipmentRequest... */)
);

Concat Method

// you don't have to create variables as you can place the streams directly in concat.
const saveBarCodes$ = this.expeditionService.getTranssmartBookingXml(request).pipe(
  concatMap(res => from(res.barcodes)),
  concatMap(barcode => this.expeditionService.saveTranssmartBarcode({
    ...saveBarcodeRequest,
    barcode
  }))
);
// no point in this being inside an operator.
const saveShipmentRequest: TranssmartSaveShipmentRequest = {
  reference: this.shipmentReferenceResult!.reference,
  price: this.transsmartDoBookingResponse!.price,
  trackingUrl: this.transsmartDoBookingResponse!.trackingUrl
};
const saveShipment$ = this.expeditionService.saveTranssmartShipment(saveShipmentRequest);
return concat(saveBarCodes$, saveShipment$);

It could be useful if you added toArray to the end of saveBarCode$ since that would cause the return result to be a tuple of an array of barcode save results and the result from saving the shipment.

over 4 years ago · Santiago Trujillo Relatório

0

Here is my final solution based on Michael D's answer. The final concatMap should result in hitting the success method in the subscribe method for every item in the printViaIpAddress method. This works perfectly.

The answer of Daniel resulted finally in hitting the success method for every concatenated observable (I think), which was not exactly what I wanted in this case.

return this.expeditionService.getTranssmartBookingXml(request).pipe(
  concatMap((response) => {
    saveShipmentRequest.price = response.price;
    saveShipmentRequest.trackingUrl = response.trackingUrl;

    return from(response.barcodes).pipe(
      concatMap((barcode) => {
        return this.expeditionService.saveTranssmartBarcode({
          ...saveBarcodeRequest,
          barcode: barcode,
        });
      })
    );
  }),
  last(),
  concatMap(() => {
    return this.expeditionService.saveTranssmartShipment(
      saveShipmentRequest
    );
  }),
  concatMap(() => {
    return this.expeditionService.getTranssmartLabels(
      transsmartBonnenXmlRequest
    );
  }),
  concatMap((response) => {
    return from(response.values).pipe(
      concatMap((label) => {
        return this.expeditionService.printViaIpAddress({
          ...printTranssmartRequest,
          label,
        });
      })
    );
  })
);
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda