You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在API返回错误时阻止Modal弹窗关闭?

问题:食品项添加功能中Modal弹窗API报错时不关闭的实现问题

需求:实现食品项添加功能,点击添加按钮打开带表单的Modal弹窗,用户填写详情提交。后端重复项检查需等待API调用完成后才能获取结果,要求API返回错误时Modal弹窗不关闭,避免用户重新填写表单。使用第三方Modal和Toast库开发时遇到代码报错问题。


原代码文件

food.component.ts

addFood(data: any){
    this.api.request('foodItem', 'POST', data).subscribe({
        next: (response: any) => {
            if (response.message == 'Added Successfully.') {
                this._toastService.showSuccess('Food added.');
            } else {
                this._toastService.showError(response.message);
            }
        },
        complete: () => this.getFood(),
        error: (error: any) => this._toastService.showError(error.message)
    });
}

food-component.html

<app-custom-table [tableData]="tableData" [form]="formData" [columnArray]="columnArray" (onAdd)="addFood($event)" (onEdit)="editFood($event)"></app-custom-table>

custom-table.component.html

<button type="button" class="btn btn-link" (click)="openModal()" [disabled]="isRowSelected"><span>Add</span></button>
<button type="button" class="btn btn-link" (click)="openModal(selectedRow)" [disabled]="isRowNotSelected"><i></i><span>Edit</span></button>

custom-table.component.ts

openModal(rowData: any = null) {
    const config: Partial<DynamicFormComponent> = {
        form: this.form,
        data: rowData
    };

    const options: NgbModalOptions = { size: 'sm', centered: true };

    const modalRef = this.ModalService.show((DynamicFormComponent), config, options).

modalRef.componentInstance.submitSubject.subscribe((result: any) => { //此处报错:Property ComponentInstance does not exist in type Observable<ModalResult<unknown>>
        if (result.Success == true && result.Data) {
            if (rowData) {
                const updatedRowData = { ...rowData, ...result.Data };
                // 若传入rowData则为编辑操作
                this.onEdit.emit(updatedRowData);
            } else { //新增操作
                this.onAdd.emit(result.Data);
            }
        }
    });
}

dynamic-form.component.ts(原标注为html,实际为ts文件)

@Output() submitSub: Subject<any> = new Subject<any>();
constructor(
  private activeModal: NgbActiveModal
 ){
 
 }

onSubmit(){
  if(this.dynamicFormGroup.valid){
    this.submitSubject.next(this.dynamicFormGroup.value)  
   this.activeModal.close(this.dynamicFormGroup.value) //此处存疑
  }
}

更新代码后遇到的问题

更新后的custom-table.component.ts代码:

openModal(rowData: any = null) {

const config: 
Partial<DynamicFormComponent> = {
form: this.form,
data: rowData
};

const options: NgbModalOptions = { 
size: 'sm', centered: true, 
backdrop: 'static' };

this.ModalService.
show((DynamicFormComponent), 
config, options);


 const activeSubscription =   

this.ngbModalService.
activeInstances
.subscribe((res: any) => {
this.modalRef = 
res[0].componentInstance;
});

setTimeout(() => {
this.modalRef.componentInstance.
 submitSubject
.subscribe((result: any) => {
if (result.Success == true && 
result.Data) {


  if (rowData) {
            
 this.onEdit.emit(updatedRowData);
  } else { 
    
    this.onAdd.emit(result.Data);
  }
  }
} );
});
}

浏览器报错:无法读取未定义的属性'componentInstance'


解决方案

核心问题分析

  1. ModalService.show()返回的是Observable而非直接的Modal实例,导致无法直接获取componentInstance
  2. 通过activeInstances和setTimeout获取实例的方式不可靠,存在异步时序问题
  3. 表单提交时自动关闭Modal,导致API报错后无法保留弹窗和表单内容

分步解决

1. 调整DynamicFormComponent的提交逻辑,取消自动关闭Modal

修改dynamic-form.component.ts:

import { Subject, Output } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';

@Output() submitSubject: Subject<any> = new Subject<any>();

constructor(private activeModal: NgbActiveModal) {}

onSubmit(){
  if(this.dynamicFormGroup.valid){
    // 只发送表单数据,不自动关闭Modal
    this.submitSubject.next(this.dynamicFormGroup.value);
  }
}

// 新增手动关闭Modal的方法,供父组件调用
closeModal() {
  this.activeModal.close();
}

2. 正确获取Modal实例并监听提交事件

修改custom-table.component.ts:

import { take } from 'rxjs';
import { DynamicFormComponent } from './path-to-dynamic-form.component';

private currentDynamicForm: DynamicFormComponent | null = null;

openModal(rowData: any = null) {
  const config: Partial<DynamicFormComponent> = {
    form: this.form,
    data: rowData
  };

  const options: NgbModalOptions = { 
    size: 'sm', 
    centered: true, 
    backdrop: 'static' // 禁止点击背景关闭弹窗
  };

  // 正确处理ModalService返回的Observable,获取组件实例
  this.ModalService.show(DynamicFormComponent, config, options)
    .pipe(take(1)) // 只取一次结果,避免内存泄漏
    .subscribe((modalResult) => {
      this.currentDynamicForm = modalResult.componentInstance as DynamicFormComponent;
      
      // 监听表单提交事件
      this.currentDynamicForm.submitSubject.pipe(take(1)).subscribe((formData) => {
        if (rowData) {
          // 编辑操作:直接提交并关闭弹窗
          const updatedRowData = { ...rowData, ...formData };
          this.onEdit.emit(updatedRowData);
          this.currentDynamicForm?.closeModal();
        } else {
          // 新增操作:仅发送数据,由API结果决定是否关闭弹窗
          this.onAdd.emit(formData);
        }
      });
    });
}

// 新增方法,供父组件调用关闭当前Modal
closeCurrentModal() {
  this.currentDynamicForm?.closeModal();
  this.currentDynamicForm = null;
}

3. 修改FoodComponent的addFood方法,控制Modal关闭时机

首先修改food-component.html,添加模板引用获取custom-table实例:

<app-custom-table #customTable 
  [tableData]="tableData" 
  [form]="formData" 
  [columnArray]="columnArray" 
  (onAdd)="addFood($event, customTable)" 
  (onEdit)="editFood($event)"></app-custom-table>

然后修改food.component.ts的addFood方法:

addFood(data: any, customTable: CustomTableComponent){
  this.api.request('foodItem', 'POST', data).subscribe({
      next: (response: any) => {
          if (response.message == 'Added Successfully.') {
              this._toastService.showSuccess('Food added.');
              // API成功后才关闭Modal
              customTable.closeCurrentModal();
              this.getFood();
          } else {
              this._toastService.showError(response.message);
              // 报错时不关闭Modal,保留表单内容
          }
      },
      error: (error: any) => {
          this._toastService.showError(error.message);
          // API请求失败时不关闭Modal
      }
  });
}

关键注意事项

  • 确认第三方Modal库的show()方法返回值结构,不同库的实例获取方式可能有差异,需参考对应文档
  • 使用RxJS的take(1)操作符避免内存泄漏
  • 禁止表单提交时自动关闭Modal,将关闭逻辑完全交给API请求结果控制
  • 保存当前Modal的组件引用,确保能在合适时机手动关闭

内容的提问来源于stack exchange,提问作者Sha Na

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 01:29:51