En aplicaciones Angular, la gestión del estado es crucial para mantener la consistencia y la sincronización de los datos a lo largo de la aplicación. Los servicios juegan un papel fundamental en la gestión del estado, proporcionando una manera centralizada y eficiente de manejar y compartir datos entre componentes.
Conceptos Clave
- Estado de la Aplicación: Representa los datos y la información que la aplicación necesita para funcionar correctamente.
- Servicios: Clases que proporcionan funcionalidades específicas y pueden ser inyectadas en componentes y otros servicios.
- Inyección de Dependencias: Mecanismo que permite a Angular proporcionar instancias de servicios a los componentes y otros servicios.
Ventajas de Usar Servicios para la Gestión de Estado
- Centralización: Los servicios permiten centralizar la lógica de negocio y el estado de la aplicación en un solo lugar.
- Reutilización: La lógica encapsulada en los servicios puede ser reutilizada en diferentes partes de la aplicación.
- Desacoplamiento: Los componentes se vuelven más simples y enfocados en la presentación, delegando la lógica de negocio a los servicios.
Ejemplo Práctico
Vamos a crear un servicio para gestionar el estado de una lista de tareas en una aplicación de tareas pendientes.
Paso 1: Crear el Servicio
Primero, creamos un servicio llamado TaskService
.
Paso 2: Definir el Servicio
En el archivo task.service.ts
, definimos el servicio con métodos para gestionar las tareas.
import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; export interface Task { id: number; title: string; completed: boolean; } @Injectable({ providedIn: 'root' }) export class TaskService { private tasksSubject: BehaviorSubject<Task[]> = new BehaviorSubject<Task[]>([]); public tasks$: Observable<Task[]> = this.tasksSubject.asObservable(); constructor() { // Inicializamos con algunas tareas const initialTasks: Task[] = [ { id: 1, title: 'Learn Angular', completed: false }, { id: 2, title: 'Build an App', completed: false } ]; this.tasksSubject.next(initialTasks); } getTasks(): Observable<Task[]> { return this.tasks$; } addTask(task: Task): void { const currentTasks = this.tasksSubject.value; this.tasksSubject.next([...currentTasks, task]); } updateTask(updatedTask: Task): void { const currentTasks = this.tasksSubject.value.map(task => task.id === updatedTask.id ? updatedTask : task ); this.tasksSubject.next(currentTasks); } deleteTask(taskId: number): void { const currentTasks = this.tasksSubject.value.filter(task => task.id !== taskId); this.tasksSubject.next(currentTasks); } }
Paso 3: Usar el Servicio en un Componente
Ahora, utilizamos el TaskService
en un componente para mostrar y gestionar las tareas.
import { Component, OnInit } from '@angular/core'; import { TaskService, Task } from './task.service'; @Component({ selector: 'app-task-list', template: ` <div *ngFor="let task of tasks"> <input type="checkbox" [checked]="task.completed" (change)="toggleTaskCompletion(task)"> {{ task.title }} <button (click)="deleteTask(task.id)">Delete</button> </div> <input [(ngModel)]="newTaskTitle" placeholder="New Task"> <button (click)="addTask()">Add Task</button> ` }) export class TaskListComponent implements OnInit { tasks: Task[] = []; newTaskTitle: string = ''; constructor(private taskService: TaskService) {} ngOnInit(): void { this.taskService.getTasks().subscribe(tasks => { this.tasks = tasks; }); } addTask(): void { const newTask: Task = { id: Date.now(), title: this.newTaskTitle, completed: false }; this.taskService.addTask(newTask); this.newTaskTitle = ''; } toggleTaskCompletion(task: Task): void { const updatedTask = { ...task, completed: !task.completed }; this.taskService.updateTask(updatedTask); } deleteTask(taskId: number): void { this.taskService.deleteTask(taskId); } }
Explicación del Código
-
TaskService:
- BehaviorSubject: Utilizamos
BehaviorSubject
para mantener y emitir el estado actual de las tareas. - Métodos CRUD: Métodos para crear, leer, actualizar y eliminar tareas.
- BehaviorSubject: Utilizamos
-
TaskListComponent:
- Suscripción a tareas: Nos suscribimos al observable
tasks$
para obtener la lista de tareas. - Métodos de interacción: Métodos para añadir, actualizar y eliminar tareas utilizando el servicio.
- Suscripción a tareas: Nos suscribimos al observable
Ejercicio Práctico
Ejercicio
- Añadir una Funcionalidad de Filtro:
- Modifica el
TaskService
para incluir un método que filtre las tareas completadas y no completadas. - Actualiza el
TaskListComponent
para permitir al usuario filtrar las tareas.
- Modifica el
Solución
- Modificar el
TaskService
:
filterTasks(completed: boolean): Observable<Task[]> { return this.tasks$.pipe( map(tasks => tasks.filter(task => task.completed === completed)) ); }
- Actualizar el
TaskListComponent
:
import { map } from 'rxjs/operators'; @Component({ selector: 'app-task-list', template: ` <div> <button (click)="showAllTasks()">All</button> <button (click)="showCompletedTasks()">Completed</button> <button (click)="showPendingTasks()">Pending</button> </div> <div *ngFor="let task of tasks"> <input type="checkbox" [checked]="task.completed" (change)="toggleTaskCompletion(task)"> {{ task.title }} <button (click)="deleteTask(task.id)">Delete</button> </div> <input [(ngModel)]="newTaskTitle" placeholder="New Task"> <button (click)="addTask()">Add Task</button> ` }) export class TaskListComponent implements OnInit { tasks: Task[] = []; newTaskTitle: string = ''; constructor(private taskService: TaskService) {} ngOnInit(): void { this.showAllTasks(); } showAllTasks(): void { this.taskService.getTasks().subscribe(tasks => { this.tasks = tasks; }); } showCompletedTasks(): void { this.taskService.filterTasks(true).subscribe(tasks => { this.tasks = tasks; }); } showPendingTasks(): void { this.taskService.filterTasks(false).subscribe(tasks => { this.tasks = tasks; }); } addTask(): void { const newTask: Task = { id: Date.now(), title: this.newTaskTitle, completed: false }; this.taskService.addTask(newTask); this.newTaskTitle = ''; } toggleTaskCompletion(task: Task): void { const updatedTask = { ...task, completed: !task.completed }; this.taskService.updateTask(updatedTask); } deleteTask(taskId: number): void { this.taskService.deleteTask(taskId); } }
Conclusión
En esta sección, hemos aprendido cómo utilizar servicios para gestionar el estado en una aplicación Angular. Hemos visto cómo crear un servicio, definir métodos para gestionar el estado y utilizar el servicio en un componente. Además, hemos implementado una funcionalidad de filtro como ejercicio práctico. La gestión del estado mediante servicios es una práctica recomendada que ayuda a mantener la lógica de negocio centralizada y los componentes más limpios y enfocados en la presentación.
Curso de Angular 2+
Módulo 1: Introducción a Angular
- ¿Qué es Angular?
- Configuración del Entorno de Desarrollo
- Tu Primera Aplicación Angular
- Arquitectura de Angular
Módulo 2: Conceptos Básicos de TypeScript
- Introducción a TypeScript
- Variables y Tipos de Datos en TypeScript
- Funciones y Funciones Flecha
- Clases e Interfaces
Módulo 3: Componentes y Plantillas
- Creación de Componentes
- Plantillas de Componentes
- Estilos de Componentes
- Interacción entre Componentes
Módulo 4: Directivas y Pipes
Módulo 5: Servicios e Inyección de Dependencias
- Introducción a los Servicios
- Creación y Uso de Servicios
- Inyección de Dependencias
- Inyectores Jerárquicos
Módulo 6: Enrutamiento y Navegación
Módulo 7: Formularios en Angular
- Formularios Basados en Plantillas
- Formularios Reactivos
- Validación de Formularios
- Formularios Dinámicos
Módulo 8: Cliente HTTP y Observables
- Introducción al Cliente HTTP
- Realizando Solicitudes HTTP
- Manejo de Respuestas HTTP
- Uso de Observables
Módulo 9: Gestión de Estado
- Introducción a la Gestión de Estado
- Uso de Servicios para la Gestión de Estado
- NgRx Store
- NgRx Effects