Ir al contenido

Tutorial: Compartir datos entre componentes con un servicio

Al terminar este tutorial vas a ser capaz de:

  • Mover el httpResource que hoy vive en tu componente de listado hacia el ArtistaService que ya creaste para crear().
  • Inyectar el servicio en un componente con inject(), en vez de llamar httpResource directamente.
  • Explicar por qué un servicio providedIn: 'root' es un singleton, y por qué eso permite compartir datos entre componentes que no se conocen.
  • Sincronizar dos componentes (ArtistCreate y ArtistList) sin @Input/@Output, usando .reload() sobre el mismo recurso compartido.

Prerrequisitos: haber completado el tutorial de crear un artista desde el front (ya tienes ArtistCreate, NuevoArtista y ArtistaService con crear()), y tu componente de listado apuntando a tu propio backend, como quedó al final del Paso 7 de “Conectar con tu front”.


2. Por qué mover el httpResource a un servicio

Sección titulada «2. Por qué mover el httpResource a un servicio»

Hoy tu componente de listado hace dos cosas a la vez: pide los datos por HTTP y los muestra en el template. Funciona, pero mezcla dos responsabilidades distintas.

Hay una segunda razón, más concreta: ArtistaService ya existe (lo creó en el tutorial anterior para crear()). Si el mismo servicio también hace la lectura, ArtistCreate y su componente de listado van a terminar compartiendo el mismo objeto — y eso es justo lo que necesita para que, al crear un artista, el listado se entere.


Cuando creaste el environment, la variable se llamaba gistUrl porque apuntaba a un Gist. Desde que la conectaste a tu propio backend ya no es cierto — es hora de que el nombre lo refleje.

En src/environments/environment.ts y src/environments/environment.development.ts, renombra la propiedad:

environment.development.ts
export const environment = {
production: false,
ARTISTAS_URL: 'http://localhost:8080/artistas',
};

ArtistaService ya existe. Agrégale la lectura, junto a la escritura que ya tiene, y actualiza crear() para usar la variable de entorno recién renombrada:

artista.service.ts
import { Injectable, inject } 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);
crear(nuevoArtista: NuevoArtista): Observable<Artista> {
return this.http.post<Artista>(environment.ARTISTAS_URL, nuevoArtista);
}
}

En tu componente de listado, quita el httpResource (ya no vive ahí) e inyecta el servicio:

artist-list.component.ts
import { Component, inject } from '@angular/core';
import { ArtistaService } from '../artista.service';
@Component({
selector: 'app-artist-list',
standalone: true,
templateUrl: './artist-list.component.html',
})
export class ArtistListComponent {
artistaService = inject(ArtistaService);
}

Y en el template, agrega el prefijo artistaService. en cada lugar donde antes leía el resource directamente:

artist-list.component.html
@if (artistaService.artistasResource.isLoading()) {
<p>Cargando artistas…</p>
}
@for (artista of artistaService.artistasResource.value() ?? []; track artista.id) {
<div class="card">{{ artista.nombre }}</div>
}

De vuelta en ArtistCreate, agregue una línea a guardar(): después de crear con éxito, refresque el recurso compartido.

artist-create.ts
this.artistaService.crear(nuevoArtista).subscribe({
next: (): void => {
this.guardando.set(false);
this.exito.set(true);
this.artistaForm.reset();
this.artistaService.artistasResource.reload();
},
error: (): void => {
this.guardando.set(false);
this.error.set(true);
},
});

Fíjese en el orden: primero se guarda el éxito y se limpia el formulario, y solo entonces se llama .reload(). Si el POST falla, error() se activa y .reload() nunca se llama — no hay nada nuevo que mostrar.

En app.html, ArtistCreate y su componente de listado van uno junto al otro, como hermanos:

app.html
<app-artist-create />
<app-artist-list />

Ninguno es el padre del otro, y no hay @Input/@Output entre ellos. La única conexión es que ambos inyectan la misma instancia de ArtistaService.


Corre tu front (ng serve) junto con tu backend. Llena el formulario y haz submit:

  • El botón debería decir “Guardando…” brevemente, y luego volver a “Crear artista”.
  • El formulario debería vaciarse.
  • En la pestaña de Red del navegador (Network), debería ver dos peticiones seguidas: el POST /artistas y, justo después, un nuevo GET /artistas disparado por el .reload(). El listado no cambia de contenido todavía (su backend no persiste), pero la petición sí se repite — esa es la parte que este tutorial quiere que verifique.

Si el backend no está corriendo, pruebe primero un error a propósito: debería ver el mensaje de error de ArtistCreate, y en ese caso el GET adicional no debería aparecer, porque .reload() nunca se llama.


Al final de este tutorial tienes:

  • ArtistaService unificado: la misma instancia lee (artistasResource) y escribe (crear()).
  • Tu componente de listado inyectando el servicio con inject(), en vez de hablar directo con la red.
  • Tu variable de entorno renombrada de gistUrl a ARTISTAS_URL.
  • ArtistCreate y tu componente de listado, sincronizados a través del mismo servicio singleton y .reload(), sin @Input/@Output entre ellos.

El mismo servicio te sirve para un caso más: mostrar el detalle de un artista al hacer clic en su card, en el tutorial de ver el detalle de un artista.