This is for a project. I need to access an array from this api: https://pokeapi.co/. I am able to access the array, which looks like this:
{"count":1050,"next":"https://pokeapi.co/api/v2/pokemon?offset=20&limit=20","previous":null,"results":[{"name":"bulbasaur","url":"https://pokeapi.co/api/v2/pokemon/1/"},{"name":"ivysaur","url":"https://pokeapi.co/api/v2/pokemon/2/"},{"name":"venusaur","url":"https://pokeapi.co/api/v2/pokemon/3/"},{"name":"charmander","url":"https://pokeapi.co/api/v2/pokemon/4/"},{"name":"charmeleon","url":"https://pokeapi.co/api/v2/pokemon/5/"},{"name":"charizard","url":"https://pokeapi.co/api/v2/pokemon/6/"},{"name":"squirtle","url":"https://pokeapi.co/api/v2/pokemon/7/"},{"name":"wartortle","url":"https://pokeapi.co/api/v2/pokemon/8/"},{"name":"blastoise","url":"https://pokeapi.co/api/v2/pokemon/9/"},{"name":"caterpie","url":"https://pokeapi.co/api/v2/pokemon/10/"},{"name":"metapod","url":"https://pokeapi.co/api/v2/pokemon/11/"},{"name":"butterfree","url":"https://pokeapi.co/api/v2/pokemon/12/"},{"name":"weedle","url":"https://pokeapi.co/api/v2/pokemon/13/"},{"name":"kakuna","url":"https://pokeapi.co/api/v2/pokemon/14/"},{"name":"beedrill","url":"https://pokeapi.co/api/v2/pokemon/15/"},{"name":"pidgey","url":"https://pokeapi.co/api/v2/pokemon/16/"},{"name":"pidgeotto","url":"https://pokeapi.co/api/v2/pokemon/17/"},{"name":"pidgeot","url":"https://pokeapi.co/api/v2/pokemon/18/"},{"name":"rattata","url":"https://pokeapi.co/api/v2/pokemon/19/"},{"name":"raticate","url":"https://pokeapi.co/api/v2/pokemon/20/"}]}
I'm trying to use interpolation, to iterate the names in my template. but since 'name' is wrapped in 'results' on the api, it can only reach it if I use results in the template. This creates an error, and it often doesn't compile as a result.
my ts file
import { Component, OnInit } from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {PokemonData} from '../../models/pokemon';
import {PokemonService} from '../../models/services/pokemon.service';
@Component({
selector: 'app-pokemon-data',
templateUrl: './pokemon-data.component.html',
styleUrls: ['./pokemon-data.component.css']
})
export class PokemonDataComponent implements OnInit {
// @Input() id: string;
public pokemonData: PokemonData[] = [];
private name: string;
constructor(private pokemonService: PokemonService, private route: ActivatedRoute) {
this.name = this.route.snapshot.paramMap.get('name');
}
onLoadPokemonByName(): void {
this.pokemonService.getPokemonbyName(this.name).subscribe(
res => {
console.log(this.name);
this.pokemonData = JSON.parse(JSON.stringify(res));
console.log(this.pokemonData);
}
);
}
ngOnInit(): void {
this.onLoadPokemonByName();
}
}
this is the html file
<p>pokemon works!</p>
<div *ngFor="let res of pokemon.results">
<div>{{res.name}}, {{res.url}}</div>
<button routerLink="/pokemondata/{{res.name}}">Pokemon Details</button>
</div>
and this is the service file
import { Injectable } from '@angular/core';
import {Observable} from 'rxjs';
import {map} from 'rxjs/operators';
import {HttpClient} from '@angular/common/http';
import {Pokemon, PokemonData} from '../pokemon';
@Injectable({
providedIn: 'root'
})
export class PokemonService {
constructor(private http: HttpClient) {
}
// http call
private baseUrl = 'https://pokeapi.co/api/v2/';
getPokemonList(): Observable<Pokemon[]> {
return this.http.get<Pokemon[]>(this.baseUrl + `pokemon?limit=150`);
}
my class file
export class Pokemon {
// this class contains properties that contain information on Pokemons
name: string;
url: string;
results: Result[];
}
export interface Result {
results: Result[];
}
my question: how do I instantiate results so that i5 doesn't cause an error in the template.
additional ts file
import {Component, Inject, OnInit} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog';
import {PokemonService} from '../../models/services/pokemon.service';
import {PokemonData} from '../../models/pokemon';
import {Chain, Evolution, Species} from '../../models/evolution';
import {ActivatedRoute} from '@angular/router';
@Component({
selector: 'app-evolution',
templateUrl: './evolution.component.html',
styleUrls: ['./evolution.component.css']
})
export class EvolutionComponent implements OnInit {
evolution: Evolution;
species: Species;
chain: Chain;
private id: string;
constructor(private pokemonService: PokemonService,
private route: ActivatedRoute) {
this.id = this.route.snapshot.paramMap.get('id');
}
getEvolutionDetails(): void {
this.pokemonService.getEvolutionData(this.id).subscribe((
res => {
console.log(this.id);
this.evolution = JSON.parse(JSON.stringify(res));
console.log(this.evolution);
}
));
}
ngOnInit(): void {
this.getEvolutionDetails();
}
}
html file
<p *ngIf="evolution.chain.species">
<div *ngFor="let res of evolution.chain.species">{{res.name}} </div>
The error I get: Cannot read property 'chain' of undefined and vendor.js:77062 ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'bulbasaur'. NgFor only supports binding to Iterables such as Arrays.
Your error is because pokemon
is null when you're trying to do the *ngFor
right? In this case you can add ?
after pokemon
in you HTML.
<div *ngFor="let res of pokemon?.results">
<div>{{res.name}}, {{res.url}}</div>
<button routerLink="/pokemondata/{{res.name}}">Pokemon Details</button>
</div>
And to be sure that you have result it will be better to add ?
after res
.
<div *ngFor="let res of pokemon?.results">
<div>{{res?.name}}, {{res?.url}}</div>
<button routerLink="/pokemondata/{{res?.name}}">Pokemon Details</button>
</div>
Or you can just do a if
<ng-container *ngIf="pokemon">
<div *ngFor="let res of pokemon?.results">
<div>{{res?.name}}, {{res?.url}}</div>
<button routerLink="/pokemondata/{{res?.name}}">Pokemon Details</button>
</div>
</ng-container>
For you second error with your EvolutionComponent
you have 2 errors:
<p *ngIf="evolution.chain.species">
<div *ngFor="let res of evolution.chain.species">{{res.name}} </div>
To fix them you can do:
<p *ngIf="evolution?.chain?.species">
<div *ngFor="let res of evolution?.chain?.species | keyvalue">{{res?.value?.name}} </div>
The ?
is to check if the value is not null.
For the error NgFor only supports binding to Iterables such as Arrays.
. It's because the field species is not an array but an object so you have to use the keyvalue
pipe. Click here for the documentation