[Reto] Pantalla detalle Pokémon: Utilizando operadores de RxJS

Rodrigo Bosarreyes
4 min readSep 28, 2023

--

AngularDex (VI)

Con lo aprendido hasta este punto deberías ser capaz de implementar la pantalla del detalle del Pokémon, te dejo los requisitos:

Yo como usuario quiero tener una página que me muestre el detalle del Pokémon. La información mostrada debe ser:

  • Nombre y número del Pokémon de la Pokédex Nacional.
  • La imagen en grande del Pokémon.
  • Descripción del Pokémon de cualquier Pokédex (puntos extra si es de la última).
  • Altura, peso, categoría y habilidad.
  • Tipos.
  • (Opcional) Debilidades.

Todos los textos deben estar en español.

También se deben mostrar en la parte superior un par de botones para poder avanzar al siguiente Pokémon (número superior) o al anterior (número inferior). En caso de ser el primero o el último en la Pokédex no se mostrará ningún texto y estará deshabilitado.

Esta pantalla debe ser accesible mediante la pantalla del listado de Pokémon cuando se pulsa sobre uno de estos elementos.

Puedes ver https://www.pokemon.com/es/pokedex/bulbasaur para lo que necesites (copiar colores, tamaños…)

Recuerda que tienes mi solución en el repositorio del proyecto, pero te recomiendo que primero intentes hacerlo por ti mismo y en caso de que tu solución sea muy diferente a la mía, ¡alégrate! ¡Eso significa que comienzas a pensar como un programador!

¿Qué tal? Se ve fácil, ¿verdad? Pues nada más lejos de la realidad, lo cierto es que la PokéAPI está codificada de una manera… extraña… lo que provoca que tengas que invocar a varios endpoints para obtener determinada información (como la descripción o las debilidades) además de realizar múltiples transformaciones, por lo que te recomiendo volver a revisar la clase donde se habla de RxJS así como investigar por tu cuenta sobre los operadores forkJoin y mergeMap.

¿No encuentras los endpoints que necesitas? Te los digo:

  • https://pokeapi.co/api/v2/pokemon/{{nombre o id del Pokémon}}: Utiliza este endpoint para obtener el ID, nombre, tipos, imagen, altura y peso.
  • https://pokeapi.co/api/v2/type/{{nombre o id del tipo}}: Utiliza este endpoint para obtener las debilidades del Pokémon.
  • https://pokeapi.co/api/v2/pokemon-species/{{id del Pokémon}}: Utiliza este endpoint para obtener la descripción, categoría y nombre en español del Pokémon. Para obtener esta URL te recomiendo que lo hagas con la propiedad “species” del JSON de respuesta del endpoint /pokemon.
  • https://pokeapi.co/api/v2/ability/{{id de la habilidad}}: Utiliza este endpoint para obtener la habilidad en español del Pokémon. Para obtener esta URL te recomiendo que lo hagas con la propiedad “abilities” del JSON de respuesta del endpoint /pokemon.

Vuelvo a mencionar la importancia de RxJS en este punto.

¿Problemas al codificar el algoritmo de las debilidades? Nuestro amigo en Quora te lo explica:

La forma en que funcionan las ventajas de tipo es simplemente matemática. Si un Pokémon es débil a un cierto tipo, recibe un daño 2 veces mayor. Si un Pokémon resiste un cierto tipo, recibe un daño 0.5 veces mayor. Y si un Pokémon es inmune a un cierto tipo, no recibe daño. Cuando se trata de Pokémon de doble tipo, simplemente multiplicamos las dos efectividades de tipo.

Por ejemplo, Parasect es un Pokémon de tipo Bicho/Planta. Bicho y Planta son débiles al Fuego. 2 x 2 = 4, así que Parasect recibirá 4 veces más daño de los ataques de tipo Fuego. Por otro lado, Bicho y Planta resisten la Tierra. 0.5 x 0.5 = 0.25, por lo que Parasect solo recibirá un 0.25 veces más daño de los ataques de tipo Tierra. En el ejemplo que mencionaste, la Roca es débil a Lucha, pero el Fantasma es inmune a ellos. 2 x 0 = 0, así que un Pokémon de tipo Roca/Fantasma aún no recibirá daño de los ataques de tipo Lucha.

Sin embargo, existen movimientos que eliminan la inmunidad de un Pokémon de tipo Fantasma a los ataques de tipo Normal y Lucha, por lo que en ese caso, el Pokémon de tipo Roca/Fantasma recibiría un daño 2 veces mayor.

Traducido a pseudocódigo sería:

Función TiposQueRecibenDobleDaño(Tipos, TiposAtaque):
TiposDobleDaño = [] # Lista para almacenar los tipos que reciben 2x daño

Para cada Tipo en Tipos:
RecibeDoble = Falso

Para cada TipoAtaque en TiposAtaque:
Si Tipo está en TipoAtaque.RecibeDobleDañoDe:
RecibeDoble = Verdadero
Romper # No es necesario verificar otros tipos de ataque

Si RecibeDoble:
TiposDobleDaño.Agregar(Tipo)

Devolver TiposDobleDaño

# Ejemplo de uso:
Tipos = [
{Nombre: "Hierba", RecibeDobleDañoDe: ["Fuego", "Hielo"]},
{Nombre: "Agua", RecibeDobleDañoDe: ["Eléctrico", "Hierba"]},
{Nombre: "Fuego", RecibeDobleDañoDe: ["Agua"]},
]

TiposAtaque = [
{Nombre: "Fuego"},
{Nombre: "Eléctrico"},
]

TiposConDobleDaño = TiposQueRecibenDobleDaño(Tipos, TiposAtaque)

Mostrar("Tipos que reciben doble daño:", TiposConDobleDaño)

Donde “Tipos” sería la respuesta de la PokéAPI y “TiposAtaque” serían los Tipos del Pokémon.

¿Sigues teniendo problemas con la obtención de datos de la PokéAPI? ¡No te preocupes! Te cuento mi solución:

pokemon.service.ts

En primer lugar, realizamos una llamada al endpoint del Pokémon. Este endpoint nos devolverá un JSON con parte de la información necesaria, como la url de “species” o el de las “abilities”, para obtener las debilidades es un proceso un poco más complicado porque entra en juego lo comentado anteriormente así que vamos a dar por supuesto que tenemos una función que devuelve el listado de debilidades.
Por cada una de estas urls necesitamos transformar o “mappear” la respuesta para que sea compatible con nuestro objeto Pokemon (de esta manera facilitará su tratamiento).
Una vez definidos nuestros observables necesitamos que se ejecuten, como en este caso no nos importa si son llamadas secuenciales (esperar a que finalice la anterior para lanzar la siguiente) podemos utilizar el operador forkJoin el cual recibe como parámetro un listado de observables (importante pasarle el Pokemon con los datos “base”).
Finalmente, mappeamos la respuesta del forkJoin para crear un objeto Pokemon con toda la información proporcionada.

Fácil ¿no? (para que luego digan que el front es solo HTML y CSS 😂).

--

--