Angular中订阅API成功后变量仍显示Undefined的问题
问题:Angular调用API获取数据后,类属性读取变量时返回Undefined
嘿,这是Angular开发中非常常见的异步数据加载问题,我来帮你理清楚原因和解决办法!
先看一下你的代码情况:
数据服务类代码
export class DataServiceService { constructor(private http: Http) { } url: string = "http://localhost:60263/api/values"; getEmployeesData(): Observable<EmployeeDetails[]> { return this.http.get(this.url).map((res: Response) => res.json()); } }
组件类代码
export class AppComponent { emp: EmployeeDetails[]; constructor(private dataServe: DataServiceService) { } ngOnInit() { this.dataServe.getEmployeesData().subscribe(res => this.emp = res); } clEmployeesCount: Number = this.emp.length; // 这里得到Undefined clShowEmployee: boolean = false; clCreateEmployee: boolean = false; }
模板代码(可正常工作)
<div *ngIf="emp"> <ul *ngFor="let user of emp"> <li>{{user.ID}}</li> </ul> </div>
问题原因
核心问题在于异步操作的执行顺序:
- 组件初始化时,
clEmployeesCount会立即赋值,这时候ngOnInit里的API请求还在后台处理,emp还是初始的undefined,所以this.emp.length自然会返回Undefined。 - 而模板里的
*ngIf="emp"会等到emp被API响应赋值后才渲染,同时Angular的变更检测机制会在数据更新后自动刷新模板,所以模板能正常显示数据。
解决方案
这里有几种靠谱的解决方式,你可以根据场景选择:
方案1:使用Getter属性动态计算数量
把clEmployeesCount改成一个getter,这样每次访问它的时候都会基于最新的emp值计算:
export class AppComponent { emp: EmployeeDetails[]; constructor(private dataServe: DataServiceService) { } ngOnInit() { this.dataServe.getEmployeesData().subscribe(res => this.emp = res); } // 改成getter,用可选链避免undefined报错,默认返回0 get clEmployeesCount(): number { return this.emp?.length || 0; } clShowEmployee: boolean = false; clCreateEmployee: boolean = false; }
方案2:在API订阅回调中直接赋值
既然API响应回来后emp才有值,那我们就在订阅成功的回调里给clEmployeesCount赋值,同时初始化时给它一个默认值:
export class AppComponent { emp: EmployeeDetails[]; clEmployeesCount: number = 0; // 初始默认值0 constructor(private dataServe: DataServiceService) { } ngOnInit() { this.dataServe.getEmployeesData().subscribe(res => { this.emp = res; this.clEmployeesCount = res.length; // 数据回来后再赋值 }); } clShowEmployee: boolean = false; clCreateEmployee: boolean = false; }
方案3:使用AsyncPipe(推荐,更符合Angular最佳实践)
这种方式不需要手动订阅Observable,Angular会帮你处理异步流和订阅销毁,还能避免内存泄漏:
首先修改组件类,把emp改成Observable类型:
export class AppComponent { emp$: Observable<EmployeeDetails[]>; // 改成Observable constructor(private dataServe: DataServiceService) { } ngOnInit() { this.emp$ = this.dataServe.getEmployeesData(); // 直接赋值Observable } clShowEmployee: boolean = false; clCreateEmployee: boolean = false; }
然后修改模板,用async管道订阅并获取数据,同时直接计算长度:
<div *ngIf="emp$ | async as emp"> <p>员工总数:{{emp.length}}</p> <ul *ngFor="let user of emp"> <li>{{user.ID}}</li> </ul> </div>
为什么模板能正常工作?
因为模板里的*ngIf="emp"会进行falsy检查,当emp是undefined的时候,这个div不会渲染;等到API响应回来,emp被赋值为数组,Angular的变更检测会触发模板更新,这时候*ngIf条件满足,就能正常渲染列表了。
内容的提问来源于stack exchange,提问作者BishtDev
相关产品推荐
相关产品推荐

