Angular中Ng-bootstrap Modal获取closeResult值的时序问题
我明白你的问题了——你现在遇到的是异步操作的典型问题:模态框的关闭结果是在Promise回调里赋值的,而你在调用open()之后立刻去读取closeResult,这时候回调还没执行,自然拿不到最新值;只有等下次打开模态框时,上一次的回调已经执行完毕,才能拿到之前的结果。
要实现“等待模态框返回结果后再执行后续逻辑”的需求,我们可以让模态框组件的open方法返回一个Promise,这样父组件就能通过async/await或者.then()来等待模态框关闭,拿到结果后再处理分支逻辑。
解决方案步骤
1. 修改模态框组件(modal-basic.ts)
把open方法改成返回Promise<string>,在result的回调里处理完closeResult后,把结果返回给调用者:
import {Component, Input, ViewChild} from '@angular/core'; import {NgbModal, ModalDismissReasons} from '@ng-bootstrap/ng-bootstrap'; @Component({ selector: 'ngbd-modal-basic', templateUrl: 'src/modal-basic.html' }) export class NgbdModalBasic { @Input() title: string; @Input() message: string; @ViewChild('content') content: any; closeResult: string; constructor(private modalService: NgbModal) {} // 修改open方法,返回Promise open(): Promise<string> { return this.modalService.open(this.content).result.then((result) => { this.closeResult = `Closed with: ${result}`; return this.closeResult; // 将结果返回给父组件 }, (reason) => { this.closeResult = `Dismissed ${this.getDismissReason(reason)}`; return this.closeResult; }); } private getDismissReason(reason: any): string { if (reason === ModalDismissReasons.ESC) { return 'by pressing ESC'; } else if (reason === ModalDismissReasons.BACKDROP_CLICK) { return 'by clicking on a backdrop'; } else { return `with: ${reason}`; } } }
2. 修改父组件(app.ts)
使用async/await语法(更直观的同步写法)或者.then()来等待模态框的结果,然后执行分支逻辑:
方式一:使用async/await
import { Component, NgModule, ViewChild } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { HttpClientModule } from '@angular/common/http'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbdModalBasic } from './modal-basic'; @Component({ selector: 'my-app', template: ` <div class="container-fluid"> <hr> <p> This is a demo plnkr forked from the <strong>ng-bootstrap</strong> project: Angular powered Bootstrap. Visit https://ng-bootstrap.github.io/ for more widgets and demos. </p> <hr> <button type="button" class="btn btn-outline-dark" (click)="openModal()">Open Modal</button> <ngbd-modal-basic [message]='message' [title]='title' #confirmationModal></ngbd-modal-basic>{{confirmationModal.closeResult}} </div> ` }) export class App { title: string; message: string; @ViewChild('confirmationModal') confirmationModal: NgbdModalBasic; // 标记方法为async async openModal() { this.title = "确认删除"; this.message = "确定要删除此项吗?"; // 等待模态框关闭,拿到结果 const result = await this.confirmationModal.open(); console.log("模态框结果:", result); // 这里执行分支逻辑 if (result.includes("Ok")) { console.log("用户确认删除,执行删除操作..."); // 你的删除逻辑写在这里 } else { console.log("用户取消删除,终止操作..."); // 取消后的逻辑 } } } @NgModule({ imports: [BrowserModule, FormsModule, ReactiveFormsModule, HttpClientModule, NgbModule.forRoot()], declarations: [App, NgbdModalBasic], bootstrap: [App] }) export class AppModule {}
方式二:使用.then()回调
如果你更习惯传统的Promise回调写法,也可以这样写:
openModal() { this.title = "确认删除"; this.message = "确定要删除此项吗?"; this.confirmationModal.open().then(result => { console.log("模态框结果:", result); // 分支逻辑 if (result.includes("Ok")) { console.log("用户确认删除,执行删除操作..."); } else { console.log("用户取消删除,终止操作..."); } }); }
为什么原来的方式不行?
原来的open方法中,modalService.open(...).result是一个异步Promise,它的.then()回调会在模态框关闭后才执行。当你在调用this.confirmationModal.open()后立刻打印closeResult时,此时回调还没触发,closeResult还是初始值undefined;只有等下一次打开模态框时,上一次的回调已经执行完毕,closeResult才会被赋值为上一次的结果。
通过让open方法返回Promise,我们就能让父组件的代码“等待”模态框关闭,拿到最新的结果后再执行后续逻辑,完美解决你的需求。
内容的提问来源于stack exchange,提问作者Stephen R. Smith

