Skip to content

IronPTSolutions/lab-dom-pokedex-state-render

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

logo_ironhack_blue 7

LAB | DOM Pokédex (State & Render)

Introducción

Has practicado el patrón State & Render construyendo un carrito de la compra. Ahora vas a aplicar el mismo patrón para crear algo más épico: tu propia Pokédex interactiva con los 150 Pokémon originales de Kanto.

Tu misión es completar IronDex, una aplicación donde puedes explorar los Pokémon, buscarlos por nombre, filtrarlos por tipo y marcar los que has capturado.

El patrón State & Render

Recuerda las reglas:

  1. El estado (state) es la única fuente de verdad
  2. Las funciones de renderizado leen el estado y actualizan el DOM
  3. Los eventos del usuario modifican el estado y llaman a render()
  4. NUNCA manipules el DOM fuera de las funciones de renderizado
  Evento del usuario (click, input, change)
         │
         ▼
  Modificar el estado (state)
         │
         ▼
  Llamar a render()
         │
         ▼
  render() lee state y actualiza el DOM

Requisitos

  • Haz fork de este repo a tu cuenta de GitHub
  • Clona el fork a tu máquina local
  • Abre el proyecto en VS Code

Entrega

Al terminar:

git add .
git commit -m "done"
git push origin main

Crea un Pull Request de tu fork hacia el repositorio original.

Instrucciones

El HTML y el CSS ya están completos. Tu único trabajo es completar las funciones en src/index.js.

Abre index.html en el navegador. Verás la estructura de la página pero sin Pokémon — las funciones de renderizado aún no están implementadas.

En tu proyecto encontrarás:

  • src/data.js — Array pokemon con los 150 Pokémon (id, nombre, tipos, sprite). No lo modifiques.
  • src/index.js — Estado, funciones auxiliares, funciones de estado y funciones de renderizado. Aquí escribes tu código.

El estado tiene esta estructura:

const state = {
  search: '',       // texto del buscador
  typeFilter: 'all', // tipo seleccionado ('all' = todos)
  captured: [],      // array de ids de Pokémon capturados
};

Iteración 1: Renderizar los Pokémon

Implementa la función renderPokemon().

Esta función debe:

  1. Seleccionar el elemento #pokemon-list
  2. Obtener la lista de Pokémon a mostrar (por ahora, usa directamente el array pokemon — en una iteración posterior usarás getFilteredPokemon())
  3. Para cada Pokémon, generar HTML con esta estructura:
<div class="pokemon-card">
  <span class="pokemon-id">#001</span>
  <span class="pokeball-icon"></span>
  <img src="https://raw.githubusercontent.com/.../1.png" alt="Bulbasaur" />
  <p class="pokemon-name">Bulbasaur</p>
  <div class="pokemon-types">
    <span class="type-badge type-Grass">Grass</span>
    <span class="type-badge type-Poison">Poison</span>
  </div>
</div>
  1. Insertar el HTML en #pokemon-list

Nota: Para formatear el id con ceros (001, 025, 150), usa String(id).padStart(3, '0').

Nota: Cada tipo necesita la clase type-{Tipo} (ej: type-Fire, type-Water) para que el CSS le aplique su color.

💡 Pista

Para generar los badges de tipo de cada Pokémon:

var typeBadges = p.types.map(function (type) {
  return '<span class="type-badge type-' + type + '">' + type + '</span>';
}).join('');

Al terminar esta iteración deberías ver los 150 Pokémon en el navegador.


Iteración 2: Capturar y liberar Pokémon

Implementa las funciones isCaptured(pokemonId) y toggleCapture(pokemonId).

isCaptured(pokemonId) debe devolver true si el id está en state.captured, y false si no.

toggleCapture(pokemonId) debe:

  1. Si el Pokémon ya está capturado, eliminarlo de state.captured
  2. Si no está capturado, añadir su id a state.captured
  3. Llamar a render()

Luego, modifica renderPokemon() para:

  • Añadir la clase CSS captured a las tarjetas de Pokémon que estén capturados
  • Hacer que al hacer clic en una tarjeta se llame a toggleCapture(pokemon.id)
💡 Pista

Para añadir condicionalmente la clase captured:

var capturedClass = isCaptured(p.id) ? ' captured' : '';
'<div class="pokemon-card' + capturedClass + '" onclick="toggleCapture(' + p.id + ')">'

Para eliminar un id del array:

state.captured = state.captured.filter(function (id) {
  return id !== pokemonId;
});

Al hacer clic en un Pokémon, su tarjeta debería cambiar de estilo (borde dorado). Haciendo clic de nuevo, vuelve a su estado normal.


Iteración 3: Panel de capturados

Implementa la función renderCapturedPanel().

Esta función debe:

  1. Actualizar #captured-count con el formato (X / 150) donde X es el número de capturados
  2. Para cada id en state.captured, buscar el Pokémon en el array pokemon y generar HTML:
<div class="captured-item">
  <img src="..." alt="Pikachu" />
  <span class="captured-name">Pikachu</span>
  <span class="captured-id">#025</span>
  <button class="btn-release"></button>
</div>
  1. Insertar el HTML en #captured-list
  2. El botón de cada captura debe llamar a toggleCapture(pokemon.id) para liberar ese Pokémon
  3. Mostrar/ocultar #empty-captured-message según si hay capturas o no
  4. Mostrar/ocultar #btn-release-all según si hay capturas o no
💡 Pista

Para buscar un Pokémon por id:

var p = pokemon.find(function (poke) {
  return poke.id === id;
});

Iteración 4: Buscar por nombre

Implementa la función setSearch(text) y la función getFilteredPokemon().

setSearch(text) debe:

  1. Actualizar state.search con el texto recibido
  2. Llamar a render()

getFilteredPokemon() debe:

  1. Filtrar el array pokemon comparando el nombre con state.search (case-insensitive)
  2. Por ahora, ignora state.typeFilter (lo añadirás en la siguiente iteración)
  3. Devolver el array filtrado

Luego:

  • Conecta el #search-input al evento input para que llame a setSearch con el valor actual del input
  • Modifica renderPokemon() para usar getFilteredPokemon() en lugar del array pokemon directamente

Implementa también renderPokemonCount() para actualizar #pokemon-count con el texto: "Mostrando X de 150 Pokémon".

💡 Pista

Filtro case-insensitive:

var matchesName = p.name.toLowerCase().includes(state.search.toLowerCase());

Conectar el input:

document.getElementById('search-input').addEventListener('input', function (event) {
  setSearch(event.target.value);
});

Escribe "pika" en el buscador y deberías ver solo a Pikachu.


Iteración 5: Filtrar por tipo

Implementa la función setTypeFilter(type).

setTypeFilter(type) debe:

  1. Actualizar state.typeFilter con el tipo recibido
  2. Llamar a render()

Luego:

  • Conecta el #type-filter (select) al evento change para que llame a setTypeFilter con el valor seleccionado
  • Completa getFilteredPokemon() para que también filtre por tipo: si state.typeFilter no es 'all', solo mostrar Pokémon que incluyan ese tipo en su array types
💡 Pista

Ambos filtros deben aplicarse a la vez:

var matchesName = p.name.toLowerCase().includes(state.search.toLowerCase());
var matchesType = state.typeFilter === 'all' || p.types.includes(state.typeFilter);
return matchesName && matchesType;

Selecciona "Fire" en el desplegable y deberías ver solo los Pokémon de tipo Fuego. Si además escribes "char", solo deberías ver Charmander, Charmeleon y Charizard.


Iteración 6: Liberar todos

Implementa la función releaseAll() y conéctala al botón #btn-release-all dentro de renderCapturedPanel().

releaseAll() debe:

  1. Vaciar state.captured
  2. Llamar a render()

Bonus — Iteración 7: localStorage

Implementa persistencia con localStorage:

  • Después de cada cambio en state.captured (en toggleCapture y releaseAll), guarda el array en localStorage
  • Al cargar la página (antes del render() inicial), recupera los capturados de localStorage si existen
💡 Pista
// Guardar
localStorage.setItem('captured', JSON.stringify(state.captured));

// Recuperar (antes del render inicial)
var saved = localStorage.getItem('captured');
if (saved) {
  state.captured = JSON.parse(saved);
}

Happy coding! ❤️

About

LAB | DOM Pokédex using the State & Render pattern - 150 original Pokémon

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors