Introducción
En Angular, la inyección de dependencias (DI) es una técnica poderosa que permite a los desarrolladores gestionar las dependencias de sus aplicaciones de manera eficiente. Los inyectores jerárquicos son una característica avanzada de Angular que permite una mayor flexibilidad y control sobre cómo se resuelven y proporcionan las dependencias en diferentes niveles de la aplicación.
Conceptos Clave
- Inyectores: Son responsables de crear instancias de dependencias y proporcionarlas a las clases que las necesitan.
- Jerarquía de Inyectores: Angular permite definir inyectores en diferentes niveles de la aplicación, creando una jerarquía. Esto significa que los inyectores pueden estar anidados y cada uno puede tener su propio conjunto de proveedores.
- Proveedores: Son objetos que indican al inyector cómo crear una instancia de una dependencia.
Jerarquía de Inyectores en Angular
En Angular, los inyectores pueden estar definidos en diferentes niveles:
- Inyector Raíz: Es el inyector global que se crea cuando se inicia la aplicación Angular. Proporciona dependencias a toda la aplicación.
- Inyectores de Módulo: Cada módulo puede tener su propio inyector, que puede proporcionar dependencias específicas a ese módulo.
- Inyectores de Componente: Cada componente puede tener su propio inyector, que puede proporcionar dependencias específicas a ese componente y sus hijos.
Ejemplo de Jerarquía de Inyectores
Consideremos una aplicación Angular con la siguiente estructura:
- AppModule
- FeatureModule
- FeatureComponent
- ChildComponent
- FeatureModule
En este caso, la jerarquía de inyectores sería:
- Inyector Raíz: Proporciona dependencias a toda la aplicación.
- Inyector de FeatureModule: Proporciona dependencias específicas a
FeatureModule
. - Inyector de FeatureComponent: Proporciona dependencias específicas a
FeatureComponent
y sus hijos, comoChildComponent
.
Configuración de Inyectores Jerárquicos
Proveedores en el Inyector Raíz
Para definir un proveedor en el inyector raíz, se utiliza el decorador @Injectable
con la propiedad providedIn: 'root'
:
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class RootService { constructor() { } }
Proveedores en el Inyector de Módulo
Para definir un proveedor en el inyector de un módulo, se utiliza la propiedad providers
en el decorador @NgModule
:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FeatureComponent } from './feature.component'; import { FeatureService } from './feature.service'; @NgModule({ declarations: [FeatureComponent], imports: [CommonModule], providers: [FeatureService] }) export class FeatureModule { }
Proveedores en el Inyector de Componente
Para definir un proveedor en el inyector de un componente, se utiliza la propiedad providers
en el decorador @Component
:
import { Component } from '@angular/core'; import { ComponentService } from './component.service'; @Component({ selector: 'app-feature', templateUrl: './feature.component.html', styleUrls: ['./feature.component.css'], providers: [ComponentService] }) export class FeatureComponent { constructor(private componentService: ComponentService) { } }
Ejemplo Práctico
Vamos a crear un ejemplo práctico para ilustrar cómo funcionan los inyectores jerárquicos en Angular.
Paso 1: Crear Servicios
Primero, creamos tres servicios: RootService
, FeatureService
y ComponentService
.
// root.service.ts import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class RootService { getMessage() { return 'Mensaje del RootService'; } } // feature.service.ts import { Injectable } from '@angular/core'; @Injectable() export class FeatureService { getMessage() { return 'Mensaje del FeatureService'; } } // component.service.ts import { Injectable } from '@angular/core'; @Injectable() export class ComponentService { getMessage() { return 'Mensaje del ComponentService'; } }
Paso 2: Configurar Módulo y Componente
Luego, configuramos el módulo y el componente para utilizar estos servicios.
// feature.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FeatureComponent } from './feature.component'; import { FeatureService } from './feature.service'; @NgModule({ declarations: [FeatureComponent], imports: [CommonModule], providers: [FeatureService] }) export class FeatureModule { } // feature.component.ts import { Component } from '@angular/core'; import { RootService } from '../root.service'; import { FeatureService } from './feature.service'; import { ComponentService } from './component.service'; @Component({ selector: 'app-feature', templateUrl: './feature.component.html', styleUrls: ['./feature.component.css'], providers: [ComponentService] }) export class FeatureComponent { constructor( private rootService: RootService, private featureService: FeatureService, private componentService: ComponentService ) { } getMessages() { console.log(this.rootService.getMessage()); console.log(this.featureService.getMessage()); console.log(this.componentService.getMessage()); } }
Paso 3: Utilizar el Componente
Finalmente, utilizamos el componente en nuestra aplicación y llamamos al método getMessages
para ver los mensajes de los diferentes servicios.
// app.component.ts import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'angular-hierarchical-injectors'; }
Ejercicio Práctico
Ejercicio
- Crea un nuevo servicio llamado
ChildService
y configúralo para que sea proporcionado en el inyector del componenteChildComponent
. - Modifica
ChildComponent
para inyectar y utilizarChildService
. - Asegúrate de que
ChildComponent
imprima un mensaje desdeChildService
cuando se inicialice.
Solución
// child.service.ts import { Injectable } from '@angular/core'; @Injectable() export class ChildService { getMessage() { return 'Mensaje del ChildService'; } } // child.component.ts import { Component, OnInit } from '@angular/core'; import { ChildService } from './child.service'; @Component({ selector: 'app-child', templateUrl: './child.component.html', styleUrls: ['./child.component.css'], providers: [ChildService] }) export class ChildComponent implements OnInit { constructor(private childService: ChildService) { } ngOnInit() { console.log(this.childService.getMessage()); } }
Conclusión
Los inyectores jerárquicos en Angular proporcionan una forma flexible y poderosa de gestionar dependencias en diferentes niveles de la aplicación. Al comprender cómo funcionan y cómo configurarlos, puedes crear aplicaciones más modulares y mantenibles. En el siguiente módulo, exploraremos cómo configurar rutas y navegar entre diferentes vistas en una aplicación Angular.
Curso de Angular
Módulo 1: Introducción a Angular
- ¿Qué es Angular?
- Configuración del Entorno de Desarrollo
- Arquitectura de Angular
- Primera Aplicación Angular
Módulo 2: Componentes de Angular
- Entendiendo los Componentes
- Creación de Componentes
- Plantillas de Componentes
- Estilos de Componentes
- Interacción entre Componentes
Módulo 3: Enlace de Datos y Directivas
- Interpolación y Enlace de Propiedades
- Enlace de Eventos
- Enlace de Datos Bidireccional
- Directivas Incorporadas
- Directivas Personalizadas
Módulo 4: 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 5: Enrutamiento y Navegación
Módulo 6: Formularios en Angular
- Formularios Basados en Plantillas
- Formularios Reactivos
- Validación de Formularios
- Formularios Dinámicos
Módulo 7: Cliente HTTP y Observables
- Introducción al Cliente HTTP
- Realizando Solicitudes HTTP
- Manejo de Respuestas HTTP
- Uso de Observables
- Manejo de Errores
Módulo 8: 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
- NgRx Entity
Módulo 9: Pruebas en Angular
- Pruebas Unitarias
- Pruebas de Componentes
- Pruebas de Servicios
- Pruebas de Extremo a Extremo
- Simulación de Dependencias
Módulo 10: Conceptos Avanzados de Angular
- Angular Universal
- Optimización del Rendimiento
- Internacionalización (i18n)
- Pipes Personalizados
- Animaciones en Angular