Trabajar con recursos en Angular no solo te permite desarrollar aplicaciones más rápidas y organizadas, sino que además te abre la puerta a construir experiencias mucho más dinámicas para tus usuarios. En este artículo vamos a ver de manera detallada cómo usar señales, servicios, peticiones HTTP, operadores de RXJS y cómo mostrar diferentes estados de usuario en tablas. Todo con ejemplos prácticos y consejos reales que puedes aplicar a tus proyectos.
¿Qué son los recursos en Angular y por qué son tan importantes?
Cuando hablamos de recursos en Angular, nos referimos a todas aquellas herramientas y utilidades que nos ayudan a conectar datos, estructurar componentes y mejorar la experiencia del usuario. Estos recursos incluyen desde el uso de señales para manejar estados reactivos, hasta la creación de servicios que centralicen la lógica de negocio.
Además, Angular nos da la posibilidad de reutilizar componentes y aprovechar el ecosistema de RXJS para manejar peticiones asincrónicas de una manera elegante. En pocas palabras, si aprendes a dominar estos recursos, tus aplicaciones darán un salto enorme en calidad y eficiencia.
Herramientas y patrones que permiten:
- Gestionar estados reactivos mediante señales.
- Organizar la lógica en servicios para que sea reutilizable.
- Conectar la aplicación con APIs externas a través de peticiones HTTP.
- Optimizar la vista con componentes reutilizables, librerías visuales e iconos.
Señales en Angular: un cambio de paradigma
Una de las grandes novedades recientes de Angular es la introducción de las señales (signals). Estas permiten un manejo más claro y eficiente del estado.
- Con
signal()
podemos crear estados reactivos que actualizan automáticamente la interfaz sin necesidad de usar mecanismos más complejos. - Es posible declarar variables como
isLoading
oisError
que cambian su valor en función de las peticiones HTTP y que luego podemos mostrar en la vista. - La ventaja es que las señales reducen mucho el código repetitivo y hacen que el flujo de datos sea más sencillo de seguir.
Por ejemplo, para controlar el estado de carga y los errores de una petición:
// country.service.ts
import { Injectable, signal } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, catchError, map, of } from 'rxjs';
import { Country } from './country.interface';
import { CountryMapper } from './country.mapper';
@Injectable({ providedIn: 'root' })
export class CountryService {
private API_URL = 'https://restcountries.com/v3.1';
isLoading = signal(false);
isError = signal<string | null>(null);
constructor(private http: HttpClient) {}
searchByCapital(query: string): Observable<Country[]> {
this.isLoading.set(true);
this.isError.set(null);
return this.http.get<any[]>(`${this.API_URL}/capital/${query.toLowerCase()}`)
.pipe(
map(countries => countries.map(c => CountryMapper.mapRestCountryToCountry(c))),
catchError(err => {
this.isError.set('No se encontró ningún país.');
return of([]);
})
);
}
}
👉 Si quieres profundizar más en el uso de señales, en el blog ya tenemos un artículo sobre Angular avanzado con señales y scroll infinito.
Servicios en Angular: separando la lógica de negocio
Los servicios son otro recurso fundamental dentro de Angular. En nuestro ejemplo práctico creamos un archivo country.service.ts
que centraliza la lógica para buscar países por capital.
Este enfoque tiene varias ventajas:
- Separación de responsabilidades: el componente se centra en la interfaz, mientras que el servicio gestiona la lógica y las peticiones.
- Reutilización de código: un mismo servicio puede ser usado en distintos componentes.
- Mayor mantenibilidad: si mañana cambia la API, solo necesitas modificar el servicio.
El uso de @Injectable
junto a provideHttpClient(withFetch())
en app.config.ts
permite que el servicio se conecte fácilmente a la API de RestCountries.
Además, gracias a la configuración en app.config.ts
:
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient, withFetch } from '@angular/common/http';
export const appConfig: ApplicationConfig = {
providers: [provideHttpClient(withFetch())]
};
habilitamos el uso de HttpClient
con fetch
de manera nativa y moderna.
Reutilización de componentes en Angular
Una de las filosofías clave de Angular es que todo es un componente. Aprovechar esta idea permite construir aplicaciones más escalables.
- Al dividir en piezas pequeñas, puedes reutilizar componentes en diferentes partes del proyecto.
- Un ejemplo claro sería una tabla que muestre usuarios o países: con solo modificar las entradas, puedes mostrar datos distintos sin tener que reescribir código.
- Además, puedes añadir estilos globales o librerías como DaisyUI para mantener la coherencia visual.
Si te interesa ir un paso más allá, te recomiendo el artículo sobre rutas hijas en Angular con módulos y lazy loading, donde se explica cómo organizar la estructura del proyecto.
Mostrar recursos en Angular con tablas dinámicas
Ahora vamos a ver cómo presentar los datos con una tabla reutilizable usando DaisyUI e Iconify:
<!-- by-capital-page.component.html -->
<div class="overflow-x-auto">
<table class="table table-zebra w-full">
<thead>
<tr>
<th>#</th>
<th>Icono</th>
<th>Bandera</th>
<th>Nombre</th>
<th>Capital</th>
<th>Población</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let country of countries; let i = index">
<td>{{ i + 1 }}</td>
<td><span class="iconify" data-icon="twemoji:flag-for-flag-{{country.capital.toLowerCase()}}"></span></td>
<td><img [src]="country.flag" alt="Bandera" width="30"/></td>
<td>{{ country.name }}</td>
<td>{{ country.capital }}</td>
<td>{{ country.population | number }}</td>
</tr>
</tbody>
</table>
</div>
Este componente aprovecha recursos en Angular como *ngFor
y pipes (number
) junto a DaisyUI para mantener un diseño responsivo.
Peticiones HTTP con Angular y RXJS
Uno de los recursos más usados en Angular es la gestión de peticiones HTTP. Gracias a HttpClient
, puedes conectarte a cualquier API externa de forma sencilla.
En nuestro caso práctico trabajamos con la API de RestCountries para obtener información de países. Al combinar esto con operadores de RXJS, como map
, catchError
o switchMap
, logramos transformar y manejar la data sin complicaciones.
map
: transforma la respuesta antes de enviarla al componente.catchError
: captura errores y permite mostrar mensajes claros al usuario.switchMap
: ideal cuando quieres cancelar una petición anterior y quedarte solo con la última.
Este patrón hace que la aplicación se sienta más fluida y evita problemas comunes como los estados intermedios que confunden a los usuarios.
Mostrar diferentes estados de usuario en Angular
Uno de los grandes retos en cualquier aplicación es gestionar los diferentes estados que puede tener el usuario al interactuar. Por ejemplo:
- Estado de carga (loading): cuando una petición está en proceso.
- Estado de error: si la API falla o el usuario escribe algo incorrecto.
- Estado de éxito: cuando los datos llegan y deben mostrarse de forma clara.
Usando señales (isLoading
, isError
) junto con plantillas condicionales en Angular, puedes mostrar iconos, mensajes o animaciones que den feedback inmediato al usuario. Esta práctica mejora la experiencia de uso y transmite profesionalidad.
Ejemplo práctico: API de países y tabla en Angular
Para entender mejor cómo funcionan los recursos en Angular, construyamos un ejemplo sencillo con la API de RestCountries:
- Creamos el servicio
CountryService
que busca países por capital. - Usamos
Postman
para verificar las rutas de la API:https://restcountries.com/v3.1/all
https://restcountries.com/v3.1/capital/{capital}
- Mapeamos los datos en una interfaz y transformamos la respuesta con
CountryMapper
. - Mostramos los datos en una tabla con columnas como:
# | Icono | Bandera | Nombre | Capital | Población | Región |
---|
<!-- by-capital-page.component.html -->
<div class="overflow-x-auto">
<table class="table table-zebra w-full">
<thead>
<tr>
<th>#</th>
<th>Icono</th>
<th>Bandera</th>
<th>Nombre</th>
<th>Capital</th>
<th>Población</th>
<th>Región</th> <!-- Nueva columna -->
</tr>
</thead>
<tbody>
<tr *ngFor="let country of countries; let i = index">
<td>{{ i + 1 }}</td>
<td>
<span class="iconify" data-icon="twemoji:flag-for-flag-{{country.capital.toLowerCase()}}"></span>
</td>
<td><img [src]="country.flag" alt="Bandera" width="30"/></td>
<td>{{ country.name }}</td>
<td>{{ country.capital }}</td>
<td>{{ country.population | number }}</td>
<td>{{ country.region }}</td> <!-- Valor de región -->
</tr>
</tbody>
</table>
</div>
Y habría que actualizar el mapper e interface:
// country.interface.ts
export interface Country {
name: string;
capital: string;
population: number;
flag: string;
region: string; // Nueva propiedad
}
// country.mapper.ts
export class CountryMapper {
static mapRestCountryToCountry(restCountry: any): Country {
return {
name: restCountry.name.common,
capital: restCountry.capital ? restCountry.capital[0] : 'No disponible',
population: restCountry.population,
flag: restCountry.flags.svg,
region: restCountry.region, // Mapeo de la región
};
}
}
Gracias a DaisyUI, la tabla se ve moderna y adaptada a dispositivos móviles. Y con Iconify, añadimos iconos que mejoran la legibilidad.
Estilo y diseño con DaisyUI e Iconify
El diseño es un recurso que no se debe subestimar. Aunque Angular se centra en la lógica, el front visual importa.
- DaisyUI facilita la creación de interfaces limpias y responsivas sin necesidad de escribir toneladas de CSS.
- Iconify te da acceso a miles de iconos listos para usar en tus componentes.
Al combinarlos, consigues una aplicación que no solo funciona bien, sino que también atrae a los usuarios visualmente.
Conclusión: domina los recursos en Angular
Como ves, trabajar con recursos en Angular te da la posibilidad de crear aplicaciones más estructuradas, reactivas y atractivas. Desde las señales para manejar estados, pasando por servicios y RXJS, hasta la reutilización de componentes y la integración de APIs, todos estos elementos forman parte de un flujo de trabajo moderno.
Si empiezas a aplicarlos en tus proyectos, notarás cómo la complejidad se reduce y la calidad del código se multiplica. Y recuerda: la clave está en practicar, experimentar y adaptar cada recurso a las necesidades reales de tu aplicación.