Angular中OnInit/AfterViewInit阶段子类别JSON偶现undefined问题
问题根源与修复方案
核心问题
- 父组件赋值错误:你把
subscribe的返回值(Subscription对象)赋值给了categories和subcategories,这会覆盖原本存储数据的变量,导致异步数据加载逻辑混乱。 - 异步请求时序问题:分类和子分类的HTTP请求是异步执行的,加载顺序不确定,子组件可能在子分类数据还未返回时就接收到
undefined。 - 未监听输入变化:子组件仅在初始化时执行一次过滤逻辑,当父组件的子分类数据加载完成后,子组件不会自动重新处理数据。
修复步骤
1. 修复Navbar组件(navbar.component.ts)
import { Component, OnInit } from '@angular/core'; import { forkJoin } from 'rxjs'; import { CategoriesService } from '../categories.service'; import { CategoryList } from 'src/assets/models/categories'; import { SubcategoriesService } from '../subcategories.service'; import { SubcategoryList } from 'src/assets/models/subcategories'; @Component({ selector: 'app-navbar', templateUrl: './navbar.component.html', styleUrls: ['./navbar.component.css'] }) export class NavbarComponent implements OnInit { categories: CategoryList | null = null; subcategories: SubcategoryList | null = null; constructor( private categoriesService: CategoriesService, private subcategoriesService: SubcategoriesService ) {} ngOnInit(): void { // 用forkJoin等待两个请求都完成后再赋值,保证数据完整性 forkJoin([ this.categoriesService.getCategories(), this.subcategoriesService.getSubcategories() ]).subscribe(([categoryData, subcategoryData]) => { this.categories = categoryData; this.subcategories = subcategoryData; }); } }
2. 修复Navbar模板(navbar.component.html)
添加*ngIf确保数据加载完成后再渲染子组件,避免传递undefined:
<div> <ul id="navLinks" class="flex-row linklist"> <li *ngFor="let category of categories?.data"> <a href="#">{{category.name}}</a> <div id="navDropdown"> <div class="container flex-row"> <!-- 确保categories和subcategories都存在时才渲染子组件 --> <app-categorydetails *ngIf="categories && subcategories" [category]="category" [subcategory]="subcategories"> </app-categorydetails> </div> </div> </li> </ul> </div>
3. 修复CategoryDetails组件(categorydetails.component.ts)
使用ngOnChanges监听输入变化,每次输入更新时重新过滤子分类:
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; import { Category } from 'src/assets/models/categories'; import { Subcategory, SubcategoryList } from 'src/assets/models/subcategories'; @Component({ selector: 'app-categorydetails', templateUrl: './categorydetails.component.html', styleUrls: ['./categorydetails.component.css'] }) export class CategorydetailsComponent implements OnChanges { @Input() category!: Category; @Input() subcategory!: SubcategoryList; subcategories: Subcategory[] = []; // 监听输入变化,每次输入更新时重新过滤 ngOnChanges(changes: SimpleChanges): void { // 检查subcategory和category是否都已赋值 if (changes['subcategory'] && this.subcategory?.data && this.category) { this.load(); } } load(): void { this.subcategories = this.subcategory.data.filter((item: Subcategory) => { return item.main_category === this.category.name; }); } }
4. 优化CategoryDetails模板(categorydetails.component.html)
添加更严谨的空值检查,可选添加无数据提示:
<img class="img-adaptive" src="https://picsum.photos/240/300"> <div id="navDropdownLinks" class="flex-row"> <div> <strong><p>NEW IN {{category.name.toUpperCase()}}</p></strong> <div *ngIf="subcategories.length > 0"> <ul class="linklist"> <li *ngFor="let item of subcategories"><a href="#"><h3>{{item.name}}</h3></a></li> </ul> </div> <!-- 可选:添加无数据提示 --> <div *ngIf="subcategories.length === 0"> <p>No subcategories available</p> </div> </div> </div> <img class="img-adaptive" src="https://picsum.photos/240/300">
关键说明
- 使用
forkJoin确保两个异步请求都完成后再渲染子组件,避免因请求时序问题导致的undefined。 - 用
ngOnChanges替代setTimeout和固定生命周期钩子,确保子组件能响应父组件数据的更新。 - 添加
*ngIf空值检查,防止在数据未加载完成时渲染组件引发错误。
内容的提问来源于stack exchange,提问作者Lancer26
相关产品推荐
相关产品推荐

