切换路由后Angular调用MongoDB API获取数据出现undefined问题
Angular路由切换后数据变为undefined的问题分析与解决
我创建了一个从MongoDB API获取数据的Angular服务,首次运行时一切正常,但切换到其他路由后再返回,数据变为undefined,刷新浏览器后恢复正常。相关代码如下:
相关代码
product.service.ts
import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable, catchError, retry, throwError, map } from 'rxjs'; import { Product } from '../interface/product'; @Injectable({ providedIn: 'root' }) export class productAPIService { constructor(private _http: HttpClient) { } getProducts(category: string): Observable<any> { const headers = new HttpHeaders().set("Content-Type", "text/plain;charset=utf-8") const requestOptions: Object = { headers: headers, responseType: "text" } return this._http.get<any>("http://localhost:3002/" + category, requestOptions).pipe( map(res => JSON.parse(res) as Array<Product>), retry(3), catchError(this.handleError) ) } track_products(category: string){ let products_lst: any; this.getProducts(category).subscribe(res => { products_lst = res; }); return products_lst; } handleError(error: HttpErrorResponse) { return throwError(() => new Error(error.message)) } }
product-list.component.ts
import { CommonModule } from '@angular/common'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { productAPIService } from '../../services/product.service'; import {NgxPaginationModule} from 'ngx-pagination'; @Component({ selector: 'app-product-list', standalone: true, imports: [CommonModule, NgxPaginationModule], templateUrl: './product-list.component.html', styleUrl: './product-list.component.css' }) export class ProductListComponent implements OnInit, OnDestroy{ p: number = 1; all_products: any = []; daychuyen_products: any = []; nhan_products: any = []; vongtay_products: any = []; bongtai_products: any = []; fil_products: any = []; constructor(private _service: productAPIService) { } ngOnInit(): void { this.daychuyen_products = this._service.track_products("daychuyen"); this.nhan_products = this._service.track_products("nhan"); this.vongtay_products = this._service.track_products("vongtay"); this.bongtai_products = this._service.track_products("bongtai"); this.all_products = [].concat(this.bongtai_products, this.nhan_products, this. vongtay_products, this.daychuyen_products).sort(() => Math.random() - 0.5); this.fil_products = this.all_products; console.log(this.fil_products); } filledStars(num: number) { return Array(num).fill(0).map((x, i) => i + 1); } ngOnDestroy(): void {} }
问题原因
- 异步逻辑处理错误:
track_products方法中,你在订阅Observable后立刻返回products_lst,此时HTTP请求还未完成,products_lst仍为初始的undefined。首次运行时可能因浏览器缓存或请求速度快,组件初始化时刚好拿到数据;但路由切换后组件重新初始化,请求未完成就赋值,导致数据为undefined。 - 组件数据拼接时机错误:
ngOnInit中直接用track_products的返回值拼接数组,此时异步请求未完成,拼接的是undefined,最终导致all_products和fil_products数据异常。
解决方案
1. 修改服务层,移除错误的同步封装
删掉track_products方法,直接暴露返回Observable的getProducts,让组件处理异步逻辑:
import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable, catchError, retry, throwError, map } from 'rxjs'; import { Product } from '../interface/product'; @Injectable({ providedIn: 'root' }) export class productAPIService { constructor(private _http: HttpClient) { } getProducts(category: string): Observable<Product[]> { const headers = new HttpHeaders().set("Content-Type", "text/plain;charset=utf-8") const requestOptions: Object = { headers: headers, responseType: "text" } return this._http.get<any>("http://localhost:3002/" + category, requestOptions).pipe( map(res => JSON.parse(res) as Product[]), retry(3), catchError(this.handleError) ) } handleError(error: HttpErrorResponse) { return throwError(() => new Error(error.message)) } }
2. 组件中正确处理异步请求
使用forkJoin同时发起多个请求,等待所有请求完成后再处理数据:
import { CommonModule } from '@angular/common'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { productAPIService } from '../../services/product.service'; import {NgxPaginationModule} from 'ngx-pagination'; import { forkJoin } from 'rxjs'; @Component({ selector: 'app-product-list', standalone: true, imports: [CommonModule, NgxPaginationModule], templateUrl: './product-list.component.html', styleUrl: './product-list.component.css' }) export class ProductListComponent implements OnInit, OnDestroy{ p: number = 1; all_products: any = []; daychuyen_products: any = []; nhan_products: any = []; vongtay_products: any = []; bongtai_products: any = []; fil_products: any = []; isLoading: boolean = true; // 可选:添加加载状态 constructor(private _service: productAPIService) { } ngOnInit(): void { // 同时发起多个分类请求,等待全部完成 forkJoin([ this._service.getProducts("daychuyen"), this._service.getProducts("nhan"), this._service.getProducts("vongtay"), this._service.getProducts("bongtai") ]).subscribe(([daychuyen, nhan, vongtay, bongtai]) => { this.daychuyen_products = daychuyen; this.nhan_products = nhan; this.vongtay_products = vongtay; this.bongtai_products = bongtai; // 所有数据获取完成后再拼接排序 this.all_products = [].concat(bongtai, nhan, vongtay, daychuyen).sort(() => Math.random() - 0.5); this.fil_products = this.all_products; this.isLoading = false; console.log(this.fil_products); }); } filledStars(num: number) { return Array(num).fill(0).map((x, i) => i + 1); } ngOnDestroy(): void {} }
3. 可选:添加加载状态提升体验
在组件模板中添加加载提示:
<div *ngIf="isLoading">加载中...</div> <div *ngIf="!isLoading"> <!-- 商品列表渲染内容 --> </div>
内容的提问来源于stack exchange,提问作者Curt
相关产品推荐
相关产品推荐

