Angular中如何处理多连锁请求后发起最终POST请求
多分支机构企业创建的异步流程实现方案
需求与现状
需要实现企业+多分支机构的创建流程:
- 每个分支机构必须先保存地址,拿到后端返回的
addressId后才能创建分支机构 - 现有代码仅支持单个分支机构,需改造为多分支适配,且要借助RxJS操作符实现异步流程控制
现有多分支数据结构:
Enterprise : { socialReason: "Apple"; siren: 1248746392; establishment: [ { name: "Apple London"; siret: "129838"; addressId: null; enterpriseId: null; }, // 更多分支机构... ] }
原单分支保存代码(仅作参考):
public onSave(): void { this.isLoading = true; const siren = this.entepriseWithEstablishmentFormGroup.controls.enterpriseFormGroup.controls.siren.value; const enterprise = this.entepriseWithEstablishmentFormGroup.controls.enterpriseFormGroup.getRawValue(); const establishment = this.entepriseWithEstablishmentFormGroup.controls.establishmentFormGroup.getRawValue(); const siret = `${siren}${establishment.siret}`; const establishmentRM = new EstablishmentRequestModel(establishment.name, siret, establishment.email, establishment.phone, null, establishment.addressId); const enterpriseRM = new EnterpriseWithEstablishmentRequestModel(enterprise.name, enterprise.siren, establishmentRM); this.isLoading = true; // create enterprise and establishment in a row this.subscriptions.add( this.enterpriseService .createEstablishmentAddress(this.addressFormGroup.getRawValue()) .pipe( map((addressId) => addressId), catchError((error: HttpErrorResponse) => throwError(() => { this.isLoading = false; this.toastr.error(this.translatePipe.transform('COMPANY.DIALOGS.CREATE.ERROR-MSG.PERSISTENCE-ERROR'), this.translatePipe.transform('ADDRESS.DIALOGS.CREATE.TITLE')); }) ), switchMap((addressId) => { enterpriseRM.establishment.addressId = addressId; this.entepriseWithEstablishmentFormGroup.controls.establishmentFormGroup.controls.addressId.patchValue(addressId); //this.showAddressForm = false; return this.enterpriseService.createEnterpriseWithEstablishment(enterpriseRM).pipe( map((response) => response), catchError((error: HttpErrorResponse) => throwError(() => { this.isLoading = false; this.toastr.error(this.translatePipe.transform('COMPANY.DIALOGS.CREATE.ERROR-MSG'), this.translatePipe.transform('COMPANY.DIALOGS.CREATE.TITLE')); }) ) ); }) ) .subscribe((response) => { this.isLoading = false; if (response !== null) { this.dialogRef.close(response); } }) );
解决方案
核心思路
- 并行保存所有分支机构地址:用
forkJoin批量发起地址保存请求,地址之间无依赖,并行处理效率更高 - 绑定地址ID与分支机构:将
forkJoin返回的addressId数组按顺序对应到各分支机构,填充addressId字段 - 创建企业及所有分支机构:构建包含所有已填充
addressId的分支机构的企业请求模型,调用创建接口
改造后的完整代码(支持批量创建分支)
public onSave(): void { this.isLoading = true; // 1. 获取表单中的企业与所有分支机构数据 const enterpriseFormData = this.entepriseWithEstablishmentFormGroup.controls.enterpriseFormGroup.getRawValue(); const establishmentsFormData = this.entepriseWithEstablishmentFormGroup.controls.establishmentsFormArray.getRawValue(); // 多分支用FormArray存储 const siren = enterpriseFormData.siren; // 2. 准备所有分支机构的地址保存请求 const addressSaveRequests$ = establishmentsFormData.map((est) => { // 替换为获取当前分支机构对应地址表单数据的逻辑 const addressData = this.getEstablishmentAddressFormData(est); return this.enterpriseService.createEstablishmentAddress(addressData).pipe( catchError((error: HttpErrorResponse) => { this.isLoading = false; this.toastr.error( this.translatePipe.transform('COMPANY.DIALOGS.CREATE.ERROR-MSG.PERSISTENCE-ERROR'), this.translatePipe.transform('ADDRESS.DIALOGS.CREATE.TITLE') ); return throwError(() => error); }) ); }); // 3. 并行处理所有地址保存请求,再创建企业+多分支 this.subscriptions.add( forkJoin(addressSaveRequests$).pipe( switchMap((addressIds: string[]) => { // 4. 将addressId对应到每个分支机构,构建请求模型 const establishmentRMs = establishmentsFormData.map((est, index) => { const siret = `${siren}${est.siret}`; return new EstablishmentRequestModel( est.name, siret, est.email, est.phone, null, addressIds[index] // 绑定对应的addressId ); }); // 5. 构建包含所有分支机构的企业请求模型 const enterpriseRM = new EnterpriseWithEstablishmentsRequestModel( enterpriseFormData.name, enterpriseFormData.siren, establishmentRMs // 传入多分支数组 ); // 6. 调用企业创建接口(需后端支持一次性创建企业+多分支) return this.enterpriseService.createEnterpriseWithEstablishments(enterpriseRM).pipe( catchError((error: HttpErrorResponse) => { this.isLoading = false; this.toastr.error( this.translatePipe.transform('COMPANY.DIALOGS.CREATE.ERROR-MSG'), this.translatePipe.transform('COMPANY.DIALOGS.CREATE.TITLE') ); return throwError(() => error); }) ); }) ).subscribe((response) => { this.isLoading = false; if (response !== null) { this.dialogRef.close(response); } }) ); } // 辅助函数:获取指定分支机构的地址表单数据(需根据实际表单结构调整) private getEstablishmentAddressFormData(establishment: any): any { const index = this.entepriseWithEstablishmentFormGroup.controls.establishmentsFormArray.controls.findIndex( ctrl => ctrl.value.siret === establishment.siret ); return this.entepriseWithEstablishmentFormGroup.controls.establishmentsFormArray.controls[index].controls.addressFormGroup.getRawValue(); }
补充:若后端不支持一次性创建多分支机构
如果后端要求先创建企业,再逐个创建分支机构,流程需调整为:
public onSave(): void { this.isLoading = true; const enterpriseFormData = this.entepriseWithEstablishmentFormGroup.controls.enterpriseFormGroup.getRawValue(); const establishmentsFormData = this.entepriseWithEstablishmentFormGroup.controls.establishmentsFormArray.getRawValue(); const siren = enterpriseFormData.siren; const addressSaveRequests$ = establishmentsFormData.map((est) => { const addressData = this.getEstablishmentAddressFormData(est); return this.enterpriseService.createEstablishmentAddress(addressData).pipe( catchError((error: HttpErrorResponse) => { this.isLoading = false; this.toastr.error( this.translatePipe.transform('COMPANY.DIALOGS.CREATE.ERROR-MSG.PERSISTENCE-ERROR'), this.translatePipe.transform('ADDRESS.DIALOGS.CREATE.TITLE') ); return throwError(() => error); }) ); }); this.subscriptions.add( forkJoin(addressSaveRequests$).pipe( // 先创建企业,获取enterpriseId switchMap((addressIds) => { const baseEnterpriseRM = new EnterpriseRequestModel(enterpriseFormData.name, enterpriseFormData.siren); return this.enterpriseService.createEnterprise(baseEnterpriseRM).pipe( map(enterprise => ({ enterpriseId: enterprise.id, addressIds })) ); }), // 批量创建分支机构,绑定enterpriseId和addressId switchMap(({ enterpriseId, addressIds }) => { const establishmentSaveRequests$ = establishmentsFormData.map((est, index) => { const siret = `${siren}${est.siret}`; const establishmentRM = new EstablishmentRequestModel( est.name, siret, est.email, est.phone, enterpriseId, addressIds[index] ); return this.enterpriseService.createEstablishment(establishmentRM).pipe( catchError(error => { this.toastr.error(this.translatePipe.transform('COMPANY.DIALOGS.CREATE.ERROR-MSG.ESTABLISHMENT'), this.translatePipe.transform('COMPANY.DIALOGS.CREATE.TITLE')); return throwError(() => error); }) ); }); return forkJoin(establishmentSaveRequests$); }) ).subscribe(() => { this.isLoading = false; this.dialogRef.close(true); }) ); }
关键RxJS操作符说明
forkJoin:并行执行多个Observable,所有请求成功完成后返回结果数组,适合无依赖的批量异步操作(如多地址保存、多分支创建)switchMap:将前一个Observable的结果转换为新的Observable,实现流程的顺序控制(如地址保存完成后触发企业创建)
注意事项
- 表单结构需适配多分支:将原单分支的
establishmentFormGroup改为establishmentsFormArray,每个数组项包含分支机构信息及对应地址表单 - 错误处理需覆盖所有异步步骤,确保任何环节失败都能关闭loading并提示用户
- 需根据后端接口能力选择对应的流程方案
内容的提问来源于stack exchange,提问作者A G
相关产品推荐
相关产品推荐

