Hago una llamada a la API que devuelve una matriz. Necesito recorrer esta matriz y realizar una nueva solicitud por elemento. El siguiente código funciona bien:
return this.expeditionService.getTranssmartBookingXml(request).pipe( concatMap((response) => { return from(response.barcodes).pipe( concatMap((barcode) => { return this.expeditionService.saveTranssmartBarcode({ ...saveBarcodeRequest, barcode: barcode, }); }) ); }) );
Sin embargo, cuando todos los artículos estén terminados, quiero hacer otra solicitud. Solo uno.
Pero cuando uso el siguiente código, el proceso se detiene cuando finaliza el primer elemento de la matriz.
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 ); }) ); })
También tenía un código ligeramente modificado donde estaba funcionando, pero luego se ejecutó la solicitud final para cada elemento de la matriz, donde solo necesita ejecutarse una vez.
Sabe alguien cómo arreglar esto? ¡¡Gracias por adelantado!!
La canalización de un operador de orden superior como concatMap
a una secuencia from
la función lo activaría para cada elemento de su matriz de origen. Necesitaría usar un operador como last
para restringir la transmisión solo al último elemento en un punto específico de la transmisión.
Aunque no haría una diferencia en la tubería last
observable interno o externo, preferiría canalizarlo al observable externo ya que se ve más elegante.
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 ); }) );
Puede usar toArray para combinar un montón de emisiones separadas en una sola matriz, o puede usar concat para procesar los dos observables en serie, ya que realmente no parece querer los resultados de guardar códigos de barras.
Yo prefiero lo segundo, pero ambos te harán querer lo que quieras y lucir más limpio que lo que tienes.
Método ToArray
return this.expeditionService.getTranssmartBookingXml(request).pipe( concatMap(res => from(res.barcodes)), concatMap(barcode => this.expeditionService.saveTranssmartBarcode({ ...saveBarcodeRequest, barcode })), toArray(), concatMap(() => /* save TrannsmartShipmentRequest... */) );
Método de concatenación
// 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$);
Podría ser útil si agregara toArray al final de saveBarCode$, ya que eso haría que el resultado devuelto fuera una tupla de una matriz de resultados de guardado de código de barras y el resultado de guardar el envío.
Aquí está mi solución final basada en la respuesta de Michael D. El concatMap final debería dar como resultado el éxito del método en el método de suscripción para cada elemento en el método printViaIpAddress. Esto funciona perfectamente.
La respuesta de Daniel resultó finalmente en alcanzar el método de éxito para cada observable concatenado (creo), que no era exactamente lo que quería en este caso.
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, }); }) ); }) );