I trying to get data from a JSON file to build a form.
Here is a portion of my template:
  <div class="form-group">
    <label for="power">Power</label>
    <select class="form-control" id="power" required>
      <option *ngFor="let p of heroes" [value]="p.level">{{p.level}}</option>
    </select>
  </div>
Here is part of the remote JSON file:
{
    "data": [
        {
            "level": "newbie",
            "places": [
                {
                    "place": "earth",
                    "categories": [
                        {
                            "category": "human",
                            "values": [
                                ...
It works with no problem and i get newbie and other choices in the select menu.
But i want to loop on places, so i edit the html template in this way:
  <div class="form-group">
    <label for="power">Power</label>
    <select class="form-control" id="power" required>
      <option *ngFor="let p of heroes[0].places" [value]="p.place">{{p.place}}</option>
    </select>
  </div>
Here is the service that i use to grab data from JSON file:
@Injectable()
export class HeroService {
    private url = 'app/mockups/heroes.json';
    constructor(private http: Http) { }
    getHeroes(): Promise<Hero[]> {
        return this.http.get(this.url)
            .toPromise()
            .then(response => response.json().data as Hero[])
            .catch();
    }
}
and here is the hero.component:
export class HeroComponent implements OnInit {
    heroes: Hero[];
    constructor(private heroService: HeroService) { }
    ngOnInit():void {
        this.getHeroes();
}
    getHeroes(): void {
        this.heroService.getHeroes().then(heroes => this.heroes = heroes);
  }
But i get "Cannot read property '0' of undefined" error.
Why?
I guess what you want is
*ngFor="let p of heroes?.data"
because heroes seems to be an object, and ngFor can only iterate array.
The level property also is in an array item.
I figured out the problem. I got this error because I'm fetching data asynchronously and when Angular tries to resolve bindings the first time data is still null therefore heroes[0] fails.
So I solved the problem initializing heroes array and using the "Elvis operator":
heroes: Hero[]; instead of heroes: Hero[] = []; in the component.
heroes[0]?.places instead of heroes[0].places in the html template.
Alternative to @Gunter Zochbauer's solution, you can declare heroesas Array property of suitable type. If you have any class with all attributes of heroes you declare heroes property as:
heroes:Array<Heroes> //Assuming class name is Heroes
And initialize it in constructor as follows:
constructor(){
...    
this.heroes=new Array<Heroes>();
}
And in your ngFor loop simply access class attributes as follows:
<option *ngFor="let p of heroes" [value]="p.place">{{p.place}}</option>
Hope it helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With