I'm studying into a Boot Camp and one of past challenge was create a Pokedex with pokeapi. I over the challenge and now I'm going to fix some thinks. I have a strange problem when I'm into details of the single pokemon. When into interpolation I put the various propriety I don't get a problem, into screen stamp it but console log give me and 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 hope someone can help me because some pokemon display and some no! i'm going crazy to found the problem!
<h2>{{ this.pokemonDetails.name?.toUpperCase() }}</h2>
I try somethings like this but orange alert appears. I'm newbie into the world of programming.
The issues are happening as it tries to find some information from a null object and throws. My guess is that your template is trying to load the template before
pokemonDetailsis fully defined, and so it cannot find the values of certain fields.You can wrap your template in
*ngIfto not show until the value is defined:Alternatively, you can use nullish operators to only go deeper in an object if the object is defined, ie.
Keep in mind that your template loads immediately and your service does not. The layout in the interim needs to be able to understand what to show.