Resource API

<< signals + rxjs Interceptores >>

Una de las nuevas características de Angular 19 es la introducción de la API Resource para trabajar con peticiones asíncronas (promesas u observables).

  • resource → Trabaja con promesas
  • rxResource → Trabaja con observables

Dentro de la función resource o rxResource debemos pasarle un objeto con una función loader que hará la carga de datos. Esta función devolverá una promesa u observable con los datos.

productsResource = resource({
  loader: () => fetch('URL productos') // Promesa
})

Acceder al valor interno

Para acceder al valor una vez está disponible, tenemos la señal interna value.

@for (product of productsResource.value(); track product.id) {
    <!-- ... -->
}

Estado de carga

Podemos comprobar el estado del recurso con la señal status, o si solo queremos saber si está realizando la petición o ya a terminado, directamente usamos isLoading (boolean). 

@if(productsResource.isLoading()) {
    <p>Cargando productos...<p>
} @else {
    <!-- Mostrar productos -->
}

Gestión de errores

Para comprobar si ha habido un error en la última petición realizada podemos consultarlo con la señal error.

@let error = productsResource.error();

@if(productsResource.isLoading()) {
    <p>Cargando productos...<p>
} @else if(error) {
    <p>Ocurrió un error {{ error | json }}</p>
} @else {
    <!-- Mostrar productos -->
}

Recarga manual

Se puede forzar al recurso a volver a realizar la petición utilizando el método reload.

@let error = productsResource.error();

@if(productsResource.isLoading()) {
    <p>Cargando productos...<p>
} @else if(error) {
    <p>Ocurrió un error {{ error | json }}</p>
    <p><button (click)="productsResource.reload()">Reintentar</button></p>
} @else {
    <!-- Mostrar productos -->
}

Vinculación de parámetros

Por medio de una función request, podemos devolver una serie de valores a los que podremos acceder en la función loader. En la función request, las señales a las que accedamos crean depedencias (como usar computed o linkedSignal) y cada vez que cambia su valor se reevalúa la función y se relanza la petición recargando los datos.

//...
export class ProductDetailComponent  {
  //...
  productResource = rxResource({
    request: () => this.id(), // Cada vez que cambia la id, carga un nuevo producto
    loader: ({request: id}) => this.#productsService.getProduct(id)
  });
  //...
}

Si necesitamos más de un parámetro, bastaría con devolver un objeto (que se recibiría en la propiedad request del loader).

export class EjemploComponent  {
  //...
  itemResource = rxResource({
    request: () => { search: this.search(), page: this.page() }, // Cada vez que cambia la id, carga un nuevo producto
    loader: ({request}) => this.#itemsService.getItems(request.search, request.page)
  });
  //...
}

Cancelando un resource

Cuando cambia el valor de los parámetros vinculados, la petición actual, si estaba en curso, se cancela generando una nueva. Esto con observables (rxResource) se gestiona automáticamente. Sin embargo, al usar promesas (resource), le tenemos que pasar un objeto AbortSignal a la promesa para cancelarla. 

productResource = resource({
  request: () => this.id(), // Cada vez que cambia la id, carga un nuevo producto
  loader: ({request: id, abortSignal}) => 
    fetch(`URL de productos/${id}`, {
      signal: abortSignal,
    })
});

<< signals + rxjs Interceptores >>