Angular的JSON数据在ngOnInit和ngAfterViewInit期间返回undefined(错误类型ERROR)。

huangapple go评论58阅读模式
英文:

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

&lt;div&gt;
    &lt;ul id=&quot;navLinks&quot; class=&quot;flex-row linklist&quot;&gt;
        &lt;li *ngFor=&quot;let category of categories.data&quot;&gt;
            &lt;a href=&quot;#&quot;&gt;{{category.name}}&lt;/a&gt;
            &lt;div id=&quot;navDropdown&quot;&gt;
                &lt;div class=&quot;container flex-row&quot;&gt;
                    &lt;app-categorydetails [category]=&quot;category&quot; [subcategory]=&quot;subcategories&quot;&gt;&lt;/app-categorydetails&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/li&gt;
    &lt;/ul&gt;
&lt;/div&gt;
       

navbar.component.ts

import { Component, OnInit } from &#39;@angular/core&#39;;
import { CategoriesService } from &#39;../categories.service&#39;;
import { CategoryList } from &#39;src/assets/models/categories&#39;;
import { SubcategoriesService } from &#39;../subcategories.service&#39;;
import { SubcategoryList } from &#39;src/assets/models/subcategories&#39;;

@Component({
  selector: &#39;app-navbar&#39;,
  templateUrl: &#39;./navbar.component.html&#39;,
  styleUrls: [&#39;./navbar.component.css&#39;]
})

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) =&gt; {
      this.categories.success = data.success;
      this.categories.message = data.message;
      this.categories.data = data.data;
    });

    this.subcategories = this.SubcategoriesService.getSubcategories().subscribe((data:SubcategoryList) =&gt; {
      this.subcategories.success = data.success;
      this.subcategories.message = data.message;
      this.subcategories.data = data.data;
    });
  }
}

categorydetails.component.html

&lt;img class=&quot;img-adaptive&quot; src=&quot;https://picsum.photos/240/300&quot;&gt;
&lt;div id=&quot;navDropdownLinks&quot; class=&quot;flex-row&quot;&gt;
    &lt;div&gt;
        &lt;strong&gt;&lt;p&gt;NEW IN {{category.name.toUpperCase()}}&lt;/p&gt;&lt;/strong&gt;
        &lt;div *ngIf=&quot;subcategories&quot;&gt;
            &lt;ul class=&quot;linklist&quot;&gt;
               &lt;li *ngFor=&quot;let item of subcategories&quot;&gt;&lt;a href=&quot;#&quot;&gt;&lt;h3&gt;{{item.name}}&lt;/h3&gt;&lt;/a&gt;&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;img class=&quot;img-adaptive&quot; src=&quot;https://picsum.photos/240/300&quot;&gt;

categorydetails.component.ts

import { Component, Input, AfterViewInit } from &#39;@angular/core&#39;;
import { CategoryList, Category } from &#39;src/assets/models/categories&#39;;
import { Subcategory, SubcategoryList } from &#39;src/assets/models/subcategories&#39;;

@Component({
  selector: &#39;app-categorydetails&#39;,
  templateUrl: &#39;./categorydetails.component.html&#39;,
  styleUrls: [&#39;./categorydetails.component.css&#39;]
})
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) =&gt; this.load());
  }

  // tried AfterViewInit but still inconsistent
  ngAfterViewInit(): void {
   //setTimeout((_:any) =&gt; this.load());
  }

  load(): void {
    // load passed JSON data
    console.log(this.subcategory.data);
    this.subcategories = this.subcategory.data.filter((item: Subcategory) =&gt; {
        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

huangapple
  • 本文由 发表于 2023年3月7日 08:30:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/75657048.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定