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

  1. Inyectores: Son responsables de crear instancias de dependencias y proporcionarlas a las clases que las necesitan.
  2. 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.
  3. 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:

  1. Inyector Raíz: Es el inyector global que se crea cuando se inicia la aplicación Angular. Proporciona dependencias a toda la aplicación.
  2. Inyectores de Módulo: Cada módulo puede tener su propio inyector, que puede proporcionar dependencias específicas a ese módulo.
  3. 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

En este caso, la jerarquía de inyectores sería:

  1. Inyector Raíz: Proporciona dependencias a toda la aplicación.
  2. Inyector de FeatureModule: Proporciona dependencias específicas a FeatureModule.
  3. Inyector de FeatureComponent: Proporciona dependencias específicas a FeatureComponent y sus hijos, como ChildComponent.

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.html -->
<app-feature></app-feature>
// 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

  1. Crea un nuevo servicio llamado ChildService y configúralo para que sea proporcionado en el inyector del componente ChildComponent.
  2. Modifica ChildComponent para inyectar y utilizar ChildService.
  3. Asegúrate de que ChildComponent imprima un mensaje desde ChildService 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

Módulo 2: Componentes de Angular

Módulo 3: Enlace de Datos y Directivas

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

Módulo 5: Enrutamiento y Navegación

Módulo 6: Formularios en Angular

Módulo 7: Cliente HTTP y Observables

Módulo 8: Gestión de Estado

Módulo 9: Pruebas en Angular

Módulo 10: Conceptos Avanzados de Angular

Módulo 11: Despliegue y Mejores Prácticas

© Copyright 2024. Todos los derechos reservados