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

调用startEditCard()时ngx-bootstrap Modal报backdrop未定义错误

Fix: Cannot read property 'backdrop' of undefined in ngx-bootstrap Modal

I've run into this exact issue before with ngx-bootstrap modals, and it almost always boils down to the modal instance not being fully initialized when you try to call show(). Let's break down why this is happening with your EditPatientComponent and EditVisitComponent, and how to fix it.

Why This Error Happens

When you call this.editPatientComponent.showEditPatientModal() from PatientComponent, Angular might not have finished initializing the editCardModal (the ModalDirective in your child component) yet. The @ViewChild in EditPatientComponent only gets populated after the component's view has fully initialized (during the AfterViewInit lifecycle hook). Since AddVisitComponent works, it's likely that you're triggering its modal after the view is ready (e.g., via a user click that happens later), while startEditCard() might be called earlier.

Solution 1: Ensure Modal is Ready Before Showing It

Let's adjust the child component to wait for the modal to be initialized, then safely call show():

Step 1: Update EditPatientComponent

Add the AfterViewInit hook and a flag to track if the modal is ready:

import { Component, EventEmitter, Input, Output, ViewChild, AfterViewInit } from '@angular/core';
import { NgForm, FormGroup, FormBuilder } from '@angular/forms';
import { ModalDirective } from 'ngx-bootstrap/modal';
import { PatientCard } from "../../../models/patientcard.model";

@Component({
 selector: 'editpatient',
 templateUrl: './editpatient.component.html',
})
export class EditPatientComponent implements AfterViewInit {
 @Input('card') card: PatientCard;
 @Output() onEditingPatient = new EventEmitter<PatientCard>();
 @ViewChild('editCardModal') editCardModal: ModalDirective;
 editCardForm: FormGroup;
 private isModalReady = false; // Track modal initialization

 constructor(private fb: FormBuilder) {
   // Initialize your form here if you haven't already
   this.editCardForm = this.fb.group({
     card: ['']
   });
 }

 ngAfterViewInit() {
   // This runs after the component's view is fully loaded
   this.isModalReady = true;
   // Optional: Patch form values when card is set (if needed)
   if (this.card) {
     this.editCardForm.patchValue(this.card);
   }
 }

 showEditPatientModal() {
   if (!this.isModalReady || !this.editCardModal) {
     // Retry after a short delay if modal isn't ready yet
     setTimeout(() => this.showEditPatientModal(), 100);
     return;
   }
   // Patch form values right before showing (in case card was updated recently)
   this.editCardForm.patchValue(this.card);
   this.editCardModal.show();
 }

 // Add your editCard and closeEditCardModal methods here
 editCard(form: FormGroup) {
   this.onEditingPatient.emit(form.value);
   this.closeEditCardModal();
 }

 closeEditCardModal() {
   this.editCardModal.hide();
 }
}

Step 2: Update PatientComponent's startEditCard Method

Make sure we only call the modal after the child component is ready:

startEditCard() {
 try {
   if (!this.editPatientComponent) {
     console.error('EditPatientComponent not found');
     return;
   }
   this.editPatientComponent.card = this.card;
   // Trigger the modal show
   this.editPatientComponent.showEditPatientModal();
 } catch (e) {
   console.error('Error opening edit modal:', e);
   alert(e);
 }
}

Solution 2: Use BsModalService for Dynamic Modals (More Reliable)

If you want to avoid @ViewChild timing issues entirely, use ngx-bootstrap's BsModalService to dynamically load your modal component. This gives you full control over when the modal is initialized.

Step 1: Update PatientComponent to Use BsModalService

import { Component, OnInit, ViewChild } from '@angular/core';
import { PatientCard } from '../../models/patientcard.model';
import { BsModalService, BsModalRef } from 'ngx-bootstrap/modal';
import { EditPatientComponent } from "./editpatient/editpatient.component";

@Component({
 selector: 'patient',
 templateUrl: './patient.component.html'
})
export class PatientComponent implements OnInit {
 // Remove the @ViewChild for EditPatientComponent
 // @ViewChild(EditPatientComponent) editPatientComponent: EditPatientComponent;
 private modalRef: BsModalRef;

 constructor(private modalService: BsModalService) {}

 startEditCard() {
   // Pass the card data to the modal component
   const initialState = {
     card: this.card
   };
   // Open the modal with the EditPatientComponent
   this.modalRef = this.modalService.show(EditPatientComponent, { initialState });
   // Listen for the output event from the modal
   this.modalRef.content.onEditingPatient.subscribe((updatedCard: PatientCard) => {
     this.editCard(updatedCard);
     this.modalRef.hide();
   });
 }

 // ... rest of your code
}

Step 2: Simplify EditPatientComponent

Remove the ModalDirective reference and use BsModalRef to control the modal:

import { Component, Input, Output, EventEmitter } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
import { BsModalRef } from 'ngx-bootstrap/modal';
import { PatientCard } from "../../../models/patientcard.model";

@Component({
 selector: 'editpatient',
 templateUrl: './editpatient.component.html',
})
export class EditPatientComponent {
 @Input() card: PatientCard;
 @Output() onEditingPatient = new EventEmitter<PatientCard>();
 editCardForm: FormGroup;

 constructor(public modalRef: BsModalRef, private fb: FormBuilder) {
   this.editCardForm = this.fb.group({
     card: ['']
   });
   // Patch form values when component initializes
   if (this.card) {
     this.editCardForm.patchValue(this.card);
   }
 }

 editCard(form: FormGroup) {
   this.onEditingPatient.emit(form.value);
 }

 closeEditCardModal() {
   this.modalRef.hide();
 }
}

Step 3: Remove Modal Markup from editpatient.component.html

You no longer need the bsModal wrapper—just keep the modal content:

<div class="modal-dialog modal-lg">
 <div class="modal-content">
 <div class="modal-header">
 <h5 class="modal-title">Редактирование карты</h5>
 <button type="button" class="close" (click)="closeEditCardModal()" aria-label="Close"></button>
 </div>
 <form [formGroup]="editCardForm" (ngSubmit)="editCard(editCardForm)">
 <div class="modal-body">
 <div class="form-group">
 <label for="card">Карта</label>
 <input type="text" class="form-control" formControlName="card" id="card" required>
 </div>
 </div>
 <div class="modal-footer">
 <button type="button" class="btn btn-warning" (click)="closeEditCardModal()">Закрыть</button>
 <button type="submit" class="btn btn-success" [disabled]="!editCardForm.valid">Редактировать</button>
 </div>
 </form>
 </div>
</div>

Why AddVisitComponent Works

Chances are you're triggering AddVisitComponent's modal via a user interaction (like a button click) that happens after the parent component's view has fully initialized. By that time, the modal instance in AddVisitComponent is already ready, so calling show() doesn't throw an error.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 09:03:41