Angular 17 Pokedex Encyclopedia

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.

Answer №1

An error is occurring because it is attempting to retrieve information from a null object and causing a throw. It appears that your template is being loaded before the complete definition of pokemonDetails, resulting in an inability to access certain field values.

To resolve this issue, consider using *ngIf to delay the display until the value is defined:

<div *ngIf="this.pokemonDetails">
  ...
</div>

Alternatively, you can utilize nullish operators to traverse deeper into an object only if the object is defined, like so:

      <div>
        <p>Pokemon type:</p>
        <p>{{ this.pokemonDetails?.types[0]?.type?.name }}</p>
        <p>{{ this.pokemonDetails?.types[1]?.type?.name }}</p>
      </div>

It's important to note that your template loads immediately while your service does not. Therefore, ensure that the layout can handle displaying appropriate content during this time.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using async/await with mysql2 in Node.js can lead to undefined rows and fields

I am facing an issue where the query below is returning undefined in rows and field even though the user table has data. How can I properly use the promise version in TypeScript? Any help would be greatly appreciated. Thank you... code import mysql from ...

Error: The service object is unable to bind to ngModel in Angular 5 due to a TypeError, as it cannot read the property 'state' of undefined within Object.eval

Within my service, I have an object declared: public caseDetails = { partyId: '', address: { state: '', city: '', zip: '', street: '' } } I am trying to bind these objects to i ...

Exploring the typing for DefaultRootState in React Redux Connect

I'm currently in the process of upgrading to the latest versions of TypeScript, React, and Redux. However, I've encountered a compiler error when using the connect function in React Redux: According to the React Redux documentation, I typed my r ...

The functionality of sockets is currently experiencing issues on the production environment when used in conjunction

I'm having trouble getting my angular project to work on production. Sockets are not functioning properly when I deploy the project on my Ubuntu 20.04 server. Everything works fine on localhost, but when I access the website on my server, I get an ERR ...

Incorporating OpenLayers and TypeScript: Issue with Event.map.forEachFeatureAtPixel, where the argument type is not compatible with the parameter type

I am currently attempting to implement Open Layers v7.2.2 with TypeScript. {When not using TypeScript, the code functions properly} function OnMapClick(event: MapBrowserEvent<UIEvent>) { event.map.forEachFeatureAtPixel(event.pixel, function(curren ...

The TypeScript error ts2322 occurs when using a generic constraint that involves keyof T and a

Trying to create a generic class that holds a pair of special pointers to keys of a generic type. Check out an example in this playground demo. const _idKey = Symbol('_idKey') const _sortKey = Symbol('_sortKey') export interface BaseSt ...

Using Ionic to invoke a function within another function in a JavaScript service

Hey everyone, I've come across an issue while working on my Ionic mobile app project. I need to call a function within another function in one of my service.js files (pushNotificationService.js). Here is the code snippet: checkForNewMessage: functi ...

Tips for displaying an element for each item chosen in a multi-select box

I currently have a situation where I am rendering for every selected element within my multiselect angular material selectbox. The rendering process functions correctly when I select an element, but the issue arises when I try to deselect one - it just ke ...

The failure to build was due to the absence of the export of ParsedQs from express-serve-static-core

Encountered the error message [@types/express]-Type 'P' is not assignable to type 'ParamsArray'. Resolved it by installing specific packages "@types/express": "^4.17.8", "@types/express-serve-static-core": ...

Having issues with installing @angular/cli globally using npm on Windows 7, the process gets stuck and does not

Encountering an issue while attempting to install the Angular CLI from npm, as it gets stuck asking to loadAllDepsIntoIdealTree. Here are the steps taken: C:\Windows\system32\node -v v6.11.1 C:\Windows\system32\npm -v 3.1 ...

loop through an intricate JSON schema using Angular 5

I've been trying to figure out how to iterate a complex JSON in Angular 5. I came across the pipe concept, but it doesn't seem to work with JSON data like the one below. I'm trying to create an expandable table using this type of data, but I ...

The guidelines specified in the root `.eslintrc.json` file of an NX workspace do not carry over to the project-level `.eslintrc.json` file

In my main .eslintrc.json file, I have set up some rules. This file contains: { "root": true, "ignorePatterns": ["**/*"], "plugins": ["@nrwl/nx", "react", "@typescript-eslint", &qu ...

Typescript does not directly manipulate values. For instance, using a statement like `if(1==2)` is prohibited

I am currently developing an Angular application with a code coverage report feature. There is a method where I need to skip certain lines based on a false condition. So, I attempted to create a function in my component like this: sum(num1:number,num2:nu ...

Steps to authenticate against a Web API in an Angular application without requiring a traditional login process

My setup involves an Angular Application and a Web Api. Previously, all users were routed to the login page upon accessing the app, where a token was created using their credentials for authentication purposes. Now, however, it is no longer mandatory for ...

The JSX element 'HeaderPublic' does not contain any construction or calling signatures

I am currently utilizing nx workspace to build the react ts application. Below is the library component: import { ReactElement } from 'react'; import styles from './header-public.module.scss'; export function HeaderPublic(): ReactElem ...

Using Angular services in a lazily loaded module

There is a service named routing.service that subscribes to routing events and updates the Translate service when a parameter changes. The constructor code looks like this: this.router.events.subscribe(val => { if (val instanceof ActivationEnd ) { ...

Do I really need to install @angular/router as a dependency in Angular CLI even if I don't plan on using it?

After creating a new Angular CLI project, I noticed that certain dependencies in the package.json file seemed unnecessary. I wanted to remove them along with FormModules and HttpModules from imports: @angular/forms": "^4.0.0", @angular/http": "^4.0.0", @a ...

Cultural adaptation in Angular

I have successfully created an Angular project with internationalization capabilities. However, I am now looking to implement it by culture, such as es-AR or en-NZ. Below are my configurations for Spanish and English in the angular.js file: "build": { ...

The services generated by OpenAPI Generator typescript-angular are experiencing failures

While utilizing version 2.4.26 of this OpenApi generator ("@openapitools/openapi-generator-cli": "^2.4.26"), I am encountering issues with Angular services (Angular Version 13.2.0). For example, the services are passing too many arguments to the Angular Ht ...

Encountering the error "Missing property '$$typeof' when trying to extend next/link in Next.js using TypeScript"

I have the following code snippet in my project: import NextLink from 'next/link' import ExternalLink from './External' type PropsType = typeof NextLink & { href: string children: React.ReactNode } export default function Link ...