Angular 7组件渲染前加载数据报错,尝试resolve无效求帮助
解决Angular 7中组件渲染前获取数据时的
Cannot read property 'dataEntries' of undefined错误 这个错误的核心原因是异步操作的时序问题,咱们一步步拆解并解决:
问题分析
forms初始化过早:你在组件类中直接初始化了forms数组,这时候dataInstance还没有被赋值——因为getActivityInstance是异步HTTP请求,请求完成前dataInstance始终是undefined,自然无法读取它的dataEntries属性。- 路由参数与请求的顺序错误:你把
getActivityInstance的请求放在了路由参数订阅的外面,这意味着请求发起时ActivityId可能还没从路由参数中拿到(路由参数订阅也是异步的),导致请求用了undefined的id,最终dataInstance还是无法被正确赋值。
解决方案一:调整异步操作顺序,数据返回后再初始化forms
修改你的组件代码,把请求逻辑放到路由参数的订阅回调中,并在数据成功返回后再初始化forms:
import { Component, OnInit } from '@angular/core'; // 导入你的其他依赖... @Component({ // 组件元数据... }) export class YourComponent implements OnInit { ActivityId: string; dataInstance: any; // 建议替换成具体的类型,比如ActivityInstance forms: any[]; // 先声明,不直接初始化 activityInstanceIdentifier: any; activityInstanceAttachement: any; constructor( private route: ActivatedRoute, private activityService: ActivityService, private sessionService: SessionService ) {} ngOnInit() { // 先订阅路由参数,确保拿到ActivityId后再发起请求 this.route.params.subscribe((params: Params) => { this.ActivityId = params['id']; // 构造请求参数 this.activityInstanceIdentifier = { "class":"eu.w4.engine.client.bpmn.w4.runtime.ActivityInstanceIdentifier", "id": this.ActivityId }; this.activityInstanceAttachement = { "class":"eu.w4.engine.client.bpmn.w4.runtime.ActivityInstanceAttachment", "dataEntriesAttached": true }; // 发起请求,数据返回后初始化forms this.activityService.getActivityInstance( this.sessionService.getPrincipal(), this.activityInstanceIdentifier, this.activityInstanceAttachement ).subscribe((ActivityInstance) => { this.dataInstance = ActivityInstance; // 数据就绪后再初始化forms this.initForms(); }, (error) => { // 增加错误处理,避免请求失败后页面卡住 console.error('获取活动实例数据失败:', error); // 可以在这里初始化空表单或者显示错误提示 }); }); } // 单独抽离表单初始化逻辑 private initForms() { this.forms = [ { dataEditionMode: DataEditionMode.DISPLAY, name:"demande", editedInstance: this.dataInstance["dataEntries"]["demande"]["value"], component: DemandeFormComponent, multiple: false } ]; } }
这样就能保证forms只有在dataInstance被正确赋值后才会初始化,不会出现访问undefined属性的错误。
解决方案二:使用路由Resolve确保组件渲染前数据已加载
你之前尝试过Resolve但没效果,大概率是配置或使用方式不对。正确的Resolve用法如下:
1. 创建Resolve服务
import { Injectable } from '@angular/core'; import { Resolve, ActivatedRouteSnapshot } from '@angular/router'; import { Observable } from 'rxjs'; // 导入你的服务和类型... @Injectable({ providedIn: 'root' }) export class ActivityInstanceResolver implements Resolve<any> { constructor( private activityService: ActivityService, private sessionService: SessionService ) {} resolve(route: ActivatedRouteSnapshot): Observable<any> { const activityId = route.params['id']; const identifier = { "class":"eu.w4.engine.client.bpmn.w4.runtime.ActivityInstanceIdentifier", "id": activityId }; const attachment = { "class":"eu.w4.engine.client.bpmn.w4.runtime.ActivityInstanceAttachment", "dataEntriesAttached": true }; // 返回请求的Observable,路由会等待这个请求完成后再渲染组件 return this.activityService.getActivityInstance( this.sessionService.getPrincipal(), identifier, attachment ); } }
2. 在路由配置中添加Resolve
import { Routes, RouterModule } from '@angular/router'; import { YourComponent } from './your-component.component'; import { ActivityInstanceResolver } from './activity-instance.resolver'; const routes: Routes = [ { path: 'your-path/:id', // 替换成你的实际路由路径 component: YourComponent, resolve: { // 定义resolve的key,后面组件中会用这个key取数据 activityInstance: ActivityInstanceResolver } } ]; @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class YourRoutingModule {}
3. 在组件中获取Resolve的数据
ngOnInit() { // 从路由快照中直接获取已加载的数据 this.dataInstance = this.route.snapshot.data['activityInstance']; // 直接初始化forms即可,因为数据已经就绪 this.initForms(); }
这种方式会让路由等待数据加载完成后再渲染组件,从根源上避免了异步数据未就绪的问题。
额外建议
- 尽量避免使用
any类型,为dataInstance和forms定义具体的TypeScript接口,这样能提前发现类型错误。 - 在模板中如果需要用到
forms,可以添加空值判断,比如*ngIf="forms",避免模板渲染时出现错误。
内容的提问来源于stack exchange,提问作者SAHBANI Med
相关产品推荐
相关产品推荐

