Angular中TypeScript无法读取undefined属性(ClosestLocation.Range)求助
问题描述
我定义了如下接口:
export interface IQuest { Id: number, lat: number, lon: number, Question:string, Answer:boolean, IsDone:boolean, Correct:boolean, Range:number }
以及如下组件:
export class AppComponent implements OnInit{ currentUserLatitude=49.8121157; currentUserLongitude=19.041796; constructor(private http:HttpClient){}; data:IQuest[]|any=[]; ClosestLocation:IQuest|any; ngOnInit(){ this.getClosestQuest(); } getClosestQuest(){ let url = "http://127.0.0.1:5153/api/GetClosest?cuLon="+this.currentUserLongitude+"&cuLat="+this.currentUserLatitude; console.log("getClosestQuest() -nowWorking"); this.http.get(url).subscribe(data=>{ console.warn(data); console.log(data); this.ClosestLocation=data; }); }
控制台能成功打印返回的数据,但调用以下函数访问ClosestLocation的属性时:
displayQuestion(){ console.warn("range: "+this.ClosestLocation.Range); }
控制台报错:
ERROR TypeError: Cannot read properties of undefined (reading 'Range') at AppComponent.displayQuestion (app.component.ts:81:61) at AppComponent.ngAfterViewInit (app.component.ts:31:10) at callHook (core.mjs:2488:22) at callHooks (core.mjs:2457:17) at executeInitAndCheckHooks (core.mjs:2408:9) at refreshView (core.mjs:10490:21) at detectChangesInternal (core.mjs:11624:9) at RootViewRef.detectChanges (core.mjs:12115:9) at ApplicationRef.tick (core.mjs:25402:22) at ApplicationRef._loadComponent (core.mjs:25440:14)
即使把ClosestLocation改成IQuest[]|any类型,问题依然存在。请问该如何正确赋值ClosestLocation以便后续访问其属性?
解决方案
核心问题是HTTP请求是异步操作,ngAfterViewInit执行时请求还未完成,ClosestLocation仍为undefined,此时访问属性就会报错。可通过以下方式解决:
1. 数据加载完成后再调用目标函数
把displayQuestion的调用放在订阅回调内部,确保ClosestLocation已经被赋值:
getClosestQuest(){ let url = "http://127.0.0.1:5153/api/GetClosest?cuLon="+this.currentUserLongitude+"&cuLat="+this.currentUserLatitude; console.log("getClosestQuest() -nowWorking"); this.http.get(url).subscribe(data=>{ console.warn(data); console.log(data); this.ClosestLocation=data; this.displayQuestion(); // 数据赋值完成后再调用 }); }
2. 使用可选链操作符规避报错
如果必须在ngAfterViewInit或其他时机调用,用可选链操作符?.防止undefined导致的错误:
displayQuestion(){ console.warn("range: "+this.ClosestLocation?.Range); }
需要默认值的话,可配合空值合并操作符:
console.warn("range: "+(this.ClosestLocation?.Range ?? 0));
3. 初始化默认值
提前给ClosestLocation设置符合接口的默认对象,避免初始状态为undefined:
ClosestLocation:IQuest = { Id: 0, lat: 0, lon: 0, Question: "", Answer: false, IsDone: false, Correct: false, Range: 0 };
这样即使请求未完成,访问属性也只会拿到默认值,不会报错。
4. 用RxJS的async管道处理(模板场景)
如果是在模板中展示属性,可将ClosestLocation改为Observable类型,配合async管道自动处理异步流:
// 组件代码 ClosestLocation$: Observable<IQuest>; ngOnInit(){ this.ClosestLocation$ = this.getClosestQuest(); } getClosestQuest(): Observable<IQuest> { let url = "http://127.0.0.1:5153/api/GetClosest?cuLon="+this.currentUserLongitude+"&cuLat="+this.currentUserLatitude; console.log("getClosestQuest() -nowWorking"); return this.http.get<IQuest>(url); }
模板中使用:
<p>Range: {{ (ClosestLocation$ | async)?.Range }}</p>
内容的提问来源于stack exchange,提问作者Samo
相关产品推荐
相关产品推荐

