Tutorial: Ver el detalle de un artista con sus álbumes
1. Objetivos de aprendizaje
Sección titulada «1. Objetivos de aprendizaje»Al terminar este tutorial vas a ser capaz de:
- Agregar un nuevo signal a un servicio que ya existe, para que varios componentes compartan “cuál es el elemento seleccionado”.
- Incluir un componente como hijo directo de otro (
ArtistDetaildentro deArtistList), sin dejar de leer la selección desde el servicio compartido. - Iterar sobre una colección anidada (
artista.albumes) con@for, el mismo patrón que ya usaste para el listado principal.
Prerrequisitos: haber completado el
tutorial de compartir datos entre componentes con un servicio
— ya tienes ArtistaService con artistasResource y crear(), y tu componente de
listado inyectándolo.
2. Agregar la selección a ArtistaService
Sección titulada «2. Agregar la selección a ArtistaService»ArtistaService ya centraliza la lectura (artistasResource) y la escritura
(crear()) de tu módulo. Ahora también va a centralizar cuál artista está
seleccionado:
import { Injectable, inject, signal } from '@angular/core';import { httpResource, HttpClient } from '@angular/common/http';import { Observable } from 'rxjs';import { Artista, NuevoArtista } from './artista.model';import { environment } from '../environments/environment';
@Injectable({ providedIn: 'root' })export class ArtistaService { private http: HttpClient = inject(HttpClient);
artistasResource = httpResource<Artista[]>(() => environment.ARTISTAS_URL); seleccionado = signal<Artista | null>(null);
crear(nuevoArtista: NuevoArtista): Observable<Artista> { return this.http.post<Artista>(environment.ARTISTAS_URL, nuevoArtista); }}3. ArtistList selecciona un artista al hacer clic
Sección titulada «3. ArtistList selecciona un artista al hacer clic»Agrega un (click) a cada card del listado:
@for (artista of artistaService.artistasResource.value() ?? []; track artista.id) { <div class="card" (click)="seleccionar(artista)"> {{ artista.nombre }} </div>}Y el método correspondiente en la clase:
seleccionar(artista: Artista): void { this.artistaService.seleccionado.set(artista);}4. Generar ArtistDetail
Sección titulada «4. Generar ArtistDetail»ng generate component artist-detailInyecta el mismo servicio y muestra el artista seleccionado junto con sus álbumes:
import { Component, inject } from '@angular/core';import { ArtistaService } from '../artista.service';
@Component({ selector: 'app-artist-detail', standalone: true, templateUrl: './artist-detail.component.html',})export class ArtistDetailComponent { artistaService = inject(ArtistaService);
cerrar(): void { this.artistaService.seleccionado.set(null); }}@if (artistaService.seleccionado(); as artista) { <div class="card mb-4"> <div class="card-body"> <h5 class="card-title">{{ artista.nombre }}</h5> <p class="text-muted">{{ artista.paisOrigen }}</p> <p>{{ artista.biografia }}</p>
<h6>Álbumes</h6> <ul> @for (album of artista.albumes; track album.id) { <li>{{ album.titulo }} ({{ album.anioLanzamiento }})</li> } </ul>
<button type="button" (click)="cerrar()">Cerrar</button> </div> </div>}5. ArtistList incluye a ArtistDetail
Sección titulada «5. ArtistList incluye a ArtistDetail»A diferencia de ArtistCreate y ArtistList (que son hermanos, sin relación entre
sí), aquí sí hay una relación directa: el listado es quien abre el detalle. Por eso
ArtistDetail va dentro del template de ArtistList, no en app.html:
import { Component, inject } from '@angular/core';import { ArtistaService } from '../artista.service';import { Artista } from '../artista.model';import { ArtistDetailComponent } from '../artist-detail/artist-detail.component';
@Component({ selector: 'app-artist-list', standalone: true, imports: [ArtistDetailComponent], templateUrl: './artist-list.component.html',})export class ArtistListComponent { artistaService = inject(ArtistaService);
seleccionar(artista: Artista): void { this.artistaService.seleccionado.set(artista); }}<app-artist-detail />
@for (artista of artistaService.artistasResource.value() ?? []; track artista.id) { <div class="card" (click)="seleccionar(artista)"> {{ artista.nombre }} </div>}6. Verificar
Sección titulada «6. Verificar»Corre ng serve. Al hacer clic en un card:
- Arriba del listado debe aparecer el detalle del artista, con sus álbumes.
- “Cerrar” debe ocultarlo.
- Hacer clic en otro card debe cambiar el detalle directamente, sin pasar por “Cerrar” primero.
¿Dónde quedaste?
Sección titulada «¿Dónde quedaste?»Al final de este tutorial tienes:
ArtistaServicecon un tercer signal,seleccionado, además deartistasResourceycrear().ArtistListseleccionando un artista al hacer clic en su card.ArtistDetail, hijo deArtistList, mostrando el artista seleccionado y sus álbumes — sin@Input, leyendo el mismo servicio compartido que el resto de la app.