英文:
Angular JSON data returning undefined (ERROR TypeError) during onInit and afterViewInit
问题
I understand that you want a translation of the code and relevant parts of your question. Here are the code and a brief explanation:
<!-- navbar.component.html -->
<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">
<app-categorydetails [category]="category" [subcategory]="subcategories"></app-categorydetails>
</div>
</div>
</li>
</ul>
</div>
// navbar.component.ts
import { Component, OnInit } from '@angular/core';
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 {
categories!: any;
subcategories!: any;
constructor(private CategoriesService: CategoriesService,
private SubcategoriesService: SubcategoriesService) {}
ngOnInit(): void {
this.categories = this.CategoriesService.getCategories().subscribe((data:CategoryList) => {
this.categories.success = data.success;
this.categories.message = data.message;
this.categories.data = data.data;
});
this.subcategories = this.SubcategoriesService.getSubcategories().subscribe((data:SubcategoryList) => {
this.subcategories.success = data.success;
this.subcategories.message = data.message;
this.subcategories.data = data.data;
});
}
}
<!-- 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">
<ul class="linklist">
<li *ngFor="let item of subcategories"><a href="#"><h3>{{item.name}}</h3></a></li>
</ul>
</div>
</div>
</div>
<img class="img-adaptive" src="https://picsum.photos/240/300">
// categorydetails.component.ts
import { Component, Input, AfterViewInit } from '@angular/core';
import { CategoryList, 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 {
@Input() category!: Category;
@Input() subcategory!: SubcategoryList;
subcategories: Subcategory[] = [];
constructor() {}
ngOnInit(): void {
setTimeout(() => this.load());
}
load(): void {
console.log(this.subcategory.data);
this.subcategories = this.subcategory.data.filter((item: Subcategory) => {
return item.main_category == this.category.name;
});
}
}
In this code, you have an Angular application with two components, NavbarComponent
and CategorydetailsComponent
, as well as some HTML templates. The issue you're facing is that sometimes the subcategories
data is undefined, and you're trying to understand why it's inconsistent.
If you have specific questions about this code or need further assistance, please let me know.
英文:
I'm new to Angular and I have a JSON data of categories
and subcategories
that I get in my navbar
component. I have a dropdown categorydetail
component that accepts a Category
object and the subcategories
JSON response so it can match the subcategories that match with the Category ID. The categories
JSON gets rendered fine, but the subcategories
is inconsistent. It sometimes gets returned correctly (as an object) and sometimes it is returned undefined. I've tried different lifecycle hooks but I just can't seem to get it to return consistently.
navbar.component.html
<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">
<app-categorydetails [category]="category" [subcategory]="subcategories"></app-categorydetails>
</div>
</div>
</li>
</ul>
</div>
navbar.component.ts
import { Component, OnInit } from '@angular/core';
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 {
categories!: any;
subcategories!: any;
constructor(private CategoriesService: CategoriesService,
private SubcategoriesService: SubcategoriesService) {}
ngOnInit(): void {
// load JSONs
this.categories = this.CategoriesService.getCategories().subscribe((data:CategoryList) => {
this.categories.success = data.success;
this.categories.message = data.message;
this.categories.data = data.data;
});
this.subcategories = this.SubcategoriesService.getSubcategories().subscribe((data:SubcategoryList) => {
this.subcategories.success = data.success;
this.subcategories.message = data.message;
this.subcategories.data = data.data;
});
}
}
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">
<ul class="linklist">
<li *ngFor="let item of subcategories"><a href="#"><h3>{{item.name}}</h3></a></li>
</ul>
</div>
</div>
</div>
<img class="img-adaptive" src="https://picsum.photos/240/300">
categorydetails.component.ts
import { Component, Input, AfterViewInit } from '@angular/core';
import { CategoryList, 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 {
@Input() category!: Category;
@Input() subcategory!: SubcategoryList;
subcategories: Subcategory[] = [];
constructor() {}
// following an answer on another thread here on SO about setting a delay but I still get undefined at times
ngOnInit(): void {
setTimeout((_:any) => this.load());
}
// tried AfterViewInit but still inconsistent
ngAfterViewInit(): void {
//setTimeout((_:any) => this.load());
}
load(): void {
// load passed JSON data
console.log(this.subcategory.data);
this.subcategories = this.subcategory.data.filter((item: Subcategory) => {
return item.main_category == this.category.name;
});
}
}
I've tried assigning the load()
function to both ngOnInit and ngAfterViewInit but both have been returning undefined at times. There are times that it works but I would like it to work all the time. I've also had a version where the function was bound to a mousemove
event on the parent li
, it works with no issues which makes me think that I might be calling the function too early. I want the data to be loaded without intervention from the user.
答案1
得分: 0
assigning it in ngOnInit is correct, but you shouldn't subscribe, you should pipe and map instead. then subscribe it in html instead using async pipe.
also your input to child component should be a stream instead of categories as well.
here's a good article to read
https://www.telerik.com/blogs/angular-basics-step-by-step-understanding-async-pipe
英文:
assigning it in ngOnInit is correct, but you shouldn't subscribe, you should pipe and map instead. then subscribe it in html instead using async pipe.
also your input to child component should be a stream instead of categories as well.
here's a good article to read
https://www.telerik.com/blogs/angular-basics-step-by-step-understanding-async-pipe
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论