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
BehaviorSubjectpara 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
TaskServicepara incluir un método que filtre las tareas completadas y no completadas. - Actualiza el
TaskListComponentpara 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
