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

  1. Estado de la Aplicación: Representa los datos y la información que la aplicación necesita para funcionar correctamente.
  2. Servicios: Clases que proporcionan funcionalidades específicas y pueden ser inyectadas en componentes y otros servicios.
  3. 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.

ng generate service task

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

  1. 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.
  2. 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.

Ejercicio Práctico

Ejercicio

  1. 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.

Solución

  1. Modificar el TaskService:
filterTasks(completed: boolean): Observable<Task[]> {
  return this.tasks$.pipe(
    map(tasks => tasks.filter(task => task.completed === completed))
  );
}
  1. 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

Módulo 2: Conceptos Básicos de TypeScript

Módulo 3: Componentes y Plantillas

Módulo 4: Directivas y Pipes

Módulo 5: Servicios e Inyección de Dependencias

Módulo 6: Enrutamiento y Navegación

Módulo 7: Formularios en Angular

Módulo 8: Cliente HTTP y Observables

Módulo 9: Gestión de Estado

Módulo 10: Pruebas en Angular

Módulo 11: Temas Avanzados

Módulo 12: Despliegue y Mejores Prácticas

© Copyright 2024. Todos los derechos reservados