Recently, I tackled a challenge during my Boot Camp where I had to create a Pokedex using pokeapi. After successfully completing the challenge, I decided to refine some aspects of it. However, I encountered an unusual issue when delving into the details of individual Pokémon. While there were no problems with interpolating various properties on the screen, the console log threw an error.
detail.component.ts:79 ERROR TypeError: Cannot read properties of undefined (reading 'type')
at DetailComponent_Template (detail.component.ts:26:12)
at executeTemplate (core.mjs:11223:9)
at refreshView (core.mjs:12746:13)
at detectChangesInView$1 (core.mjs:12970:9)
at detectChangesInViewIfAttached (core.mjs:12933:5)
at detectChangesInComponent (core.mjs:12922:5)
at detectChangesInChildComponents (core.mjs:12983:9)
at refreshView (core.mjs:12796:13)
at detectChangesInView$1 (core.mjs:12970:9)
at detectChangesInViewIfAttached (core.mjs:12933:5)
@Component({
selector: 'app-detail',
standalone: true,
imports: [DetailComponent],
template: `
<div>
<h2>{{ this.pokemonDetails.name.toUpperCase() }}</h2>
<img
src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/home/{{
pokemonId
}}.png"
alt="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/home/{{
pokemonId
}}.png"
height="100"
/>
<div>
<p>Pokemon type:</p>
<p>{{ this.pokemonDetails.types[0].type.name }}</p>
<p>{{ this.pokemonDetails.types[1].type.name }}</p>
</div>
<div>
<p>
Description:
{{ this.speciesDetail.flavor_text_entries[0].flavor_text }}
</p>
</div>
<div>
<p>BASE STAT:</p>
<ul>
<li>
<p>HP:{{ this.pokemonDetails.stats[0].base_stat }}</p>
</li>
<li>
<p>ATK:{{ this.pokemonDetails.stats[1].base_stat }}</p>
</li>
<li>
<p>DEF:{{ this.pokemonDetails.stats[2].base_stat }}</p>
</li>
<li>
<p>S. ATK:{{ this.pokemonDetails.stats[3].base_stat }}</p>
</li>
<li>
<p>S. DEF:{{ this.pokemonDetails.stats[4].base_stat }}</p>
</li>
<li>
<p>SPEED:{{ this.pokemonDetails.stats[5].base_stat }}</p>
</li>
</ul>
</div>
</div>
`,
styles: ``,
})
export default class DetailComponent implements OnInit {
pokemonId!: number;
pokemonDetails!: Pokemon;
speciesDetail!: Species;
public service = inject(StateService);
constructor(private route: ActivatedRoute) {}
ngOnInit(): void {
this.route.params.subscribe((params) => {
this.pokemonId = params['id'];
this.service.getPokemonById(this.pokemonId).subscribe((pokemon) => {
this.pokemonDetails = pokemon;
console.log(this.pokemonDetails);
});
this.service
.getPokemonSpeciesDetailsById(this.pokemonId)
.subscribe((pokemon) => {
this.speciesDetail = pokemon;
console.log(this.speciesDetail);
});
});
}
}
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable, forkJoin } from 'rxjs';
import { map, mergeMap } from 'rxjs/operators';
import { Pokemon, PokemonResults } from '../../model/pokemon';
@Injectable({
providedIn: 'root',
})
export class StateService {
private pokemonListSubject: BehaviorSubject<Pokemon[]> = new BehaviorSubject<
Pokemon[]
>([]);
public pokemonList$: Observable<Pokemon[]> =
this.pokemonListSubject.asObservable();
constructor(private http: HttpClient) {}
fetchPokemonList(offset: number = 0, limit: number = 20): Observable<void> {
const url = `https://pokeapi.co/api/v2/pokemon/?offset=${offset}&limit=${limit}`;
return this.http.get<PokemonResults>(url).pipe(
map((data: PokemonResults) => data.results),
mergeMap((pokemonResults) =>
this.fetchDetailedPokemonData(pokemonResults)
),
map((detailedPokemonList) => {
this.pokemonListSubject.next(detailedPokemonList);
})
);
}
private fetchDetailedPokemonData(
pokemonList: { name: string; url: string }[]
): Observable<Pokemon[]> {
return forkJoin(
pokemonList.map((pokemon) => this.http.get<Pokemon>(pokemon.url))
);
}
getPokemonById(id: number): Observable<Pokemon> {
const url = `https://pokeapi.co/api/v2/pokemon/${id}`;
return this.http.get<Pokemon>(url);
}
getPokemonSpeciesDetailsById(id: number): Observable<any> {
const url = `https://pokeapi.co/api/v2/pokemon-species/${id}`;
return this.http.get<any>(url);
}
}
I've been struggling with inconsistent Pokémon display issues and have attempted solutions like the one above, but an error keeps popping up. As a beginner in the programming world, I hope someone can assist me in resolving this perplexing problem!
<h2>{{ this.pokemonDetails.name?.toUpperCase() }}</h2>
I try somethings like this but orange alert appears. I'm newbie into the world of programming.