Angular组件调用子组件模板元素报错:Cannot read properties of undefined (reading 'pdfData')
问题:Angular父组件调用子组件模板元素时出现“Cannot read properties of undefined (reading 'pdfData')”错误
我有两个Angular组件:UserPatientsReportFormComponent(父组件)和UserPatientsReportFormTemplateComponent(子组件),想要在父组件中调用子组件的模板元素#pdfData,但报错“Cannot read properties of undefined (reading 'pdfData')”。以下是相关代码,需要修改方案:
子组件(UserPatientsReportFormTemplateComponent)模板代码
<div id="pdfData" #pdfData> <table *ngFor="let hubxReport of hubxReportList; let i=index"> <tr> <th>{{hubxReport.categoryName}} + "Test"</th> </tr> <tr> <th>{{column}}</th> </tr> <tr *ngFor="let item of hubxReport.hubxDataItems"> <td></td> <td>{{item.itemTitle}}</td> <td>{{item.itemValue}}</td> <td>{{item.itemUnit}}</td> <td>{{item.normalRange}}</td> </tr> </table> </div>
子组件(UserPatientsReportFormTemplateComponent)逻辑代码
export class UserPatientsReportFormTemplateComponent implements OnInit { clientId : number; hubxReportList : Array<HubxDataModel> = []; @ViewChild('pdfData') public pdfData: ElementRef; constructor(private activatedRoute: ActivatedRoute,private usersService: UsersService,private commonService:CommonService) { } ngOnInit(): void { this.activatedRoute.queryParams.subscribe(params => { this.clientId = params.id == undefined ? null : this.commonService.encryptValue(params.id, false); }); this.getHubxReport(); } getHubxReport() { this.usersService.getHubxReport(this.clientId).subscribe((response: ResponseModel) => { if (response != null && response.data != null && response.data.length > 0) { this.hubxReportList = response.data; } }); } }
父组件(UserPatientsReportFormComponent)部分代码
export class UserPatientsReportFormComponent implements OnInit { @ViewChild(UserPatientsReportFormTemplateComponent) userPatientReportFormTemplate: UserPatientsReportFormTemplateComponent; }
父组件中调用模板元素的函数代码
downloadPDF(isSubmit:any) { let doc = new jsPDF(); let rows: Array<any> = []; let header: Array<any> = []; let medicineInfo: any; let physicianInfo: any; let content= this.userPatientReportFormTemplate.pdfData.nativeElement; //---错误发生在这里--- let _elementHandlers = { '#editor':function(element,renderer){ return true; } }; doc.fromHTML(content.innerHTML,15,15,{ 'width':190, 'elementHandlers':_elementHandlers }); }
修改方案
1. 确保父组件正确获取子组件实例
- 若父组件模板中
UserPatientsReportFormTemplateComponent是通过*ngIf等条件渲染的,需确保调用downloadPDF时组件已渲染完成;Angular 8+中@ViewChild默认static: false,会在视图初始化后获取实例。 - 若组件是静态渲染(无条件渲染逻辑),可设置
static: true确保在ngOnInit阶段就能获取实例:
@ViewChild(UserPatientsReportFormTemplateComponent, { static: true }) userPatientReportFormTemplate: UserPatientsReportFormTemplateComponent;
2. 确保子组件的pdfData元素已初始化
子组件的@ViewChild('pdfData')会在ngAfterViewInit生命周期钩子后才完成初始化。如果父组件在ngOnInit中直接调用downloadPDF,此时子组件的pdfData可能还未就绪:
- 确保
downloadPDF通过用户交互触发(比如按钮点击),而非在组件初始化阶段自动执行;或在父组件的ngAfterViewInit中执行相关逻辑。
3. 子组件封装获取元素的方法(推荐)
遵循组件封装原则,不要直接访问子组件的属性,而是在子组件中暴露方法返回目标元素:
// 子组件新增方法 getPdfElement(): ElementRef | undefined { return this.pdfData; }
父组件中调用该方法:
downloadPDF(isSubmit:any) { const pdfElement = this.userPatientReportFormTemplate.getPdfElement(); if (!pdfElement) { console.error('PDF元素未初始化'); return; } let content = pdfElement.nativeElement; // 后续jsPDF逻辑不变 }
4. 确保异步数据加载完成后再生成PDF
子组件的表格内容依赖异步加载的hubxReportList,需确保数据加载完成后再执行PDF生成:
// 子组件中添加数据加载完成标志 isDataLoaded = false; getHubxReport() { this.usersService.getHubxReport(this.clientId).subscribe((response: ResponseModel) => { if (response != null && response.data != null && response.data.length > 0) { this.hubxReportList = response.data; this.isDataLoaded = true; // 标记数据加载完成 } }); }
父组件中先判断标志再执行:
downloadPDF(isSubmit:any) { if (!this.userPatientReportFormTemplate?.isDataLoaded) { console.error('数据未加载完成,无法生成PDF'); return; } // 后续逻辑不变 }
内容的提问来源于stack exchange,提问作者Manipuri Vlogs
相关产品推荐
相关产品推荐

