9 - Inyección de Dependencias

Inyección de Dependencias

Uno de las grandes novedades de Angular ( entre otras cosas ) es la inyección de dependencias, este patron ( https://es.wikipedia.org/wiki/Inyección_de_dependencias ) es un patron de diseño orientado a objetos.

La IDEA de la ID (Inyección de dependencias ) es muy simple , si tenes un componente que depende de un servicio, no creas ese servicio (en el componente ) si no que en el constructor lo solicitas y Angular te lo trae.

De esta forma, el codigo esta desacoplado, ya que el que el servicio se encarga de lo que debe, y el componente solamente lo consume.

Esto nos sirve para poder testear como se debe y que sea mas facil.

Angular viene con un sistema de inyección de dependencia. Para ver cómo se puede usar, veamos el siguiente componente, que muestra una lista de tickets usando la directiva for:

@Component({
  selector: 'ticket-component',
  template: `
    <h2>Tickets:</h2>
    <ticket *ngFor="let t of tickets" [ticket]="t"></ticket>
  `
})
class TicketCmp {
  constructor() { //..obtenemos la data }
}

Ahora crearemos un mock up para los datos que tenemos que iterar

class TicketsMockUp {
  fetchTickets() {
    return [
      { id: 1, text: 'No me funciona la impresora', state: 'open' },
      { id: 2, text: 'No me funciona el mouse', state: 'close' }
    ];
  }
}

Ahora lo que necesitamos en nuestro componente es obtener los datos de este servicio...

¿Como lo hacemos?

Creamos una instancia del mismo en nuestro componente, de la siguiente forma:

constructor() {
    const mockUp = new TicketsMockUp();
    this.tickets = mockUp.fetchTickets();
}

Hasta ahi todo genial para "entender" o hacer una mini demo, pero realmente NO es para producción, para ello deberiamos utilizar lo siguiente =>

class TicketCmp {
  constructor(mockUp:TicketsMockUp) {
    this.tickets = mockUp.fetchTickets();
  }
}

Lo que hicimos, fue utilizar la DI para traer nuestro "servicio" (mejor dicho mockup) , Angular lo que hizo fue crear una instancia de TicketsMockUp.

Este "provider"/"servicio"/"mockup" que cremos ( un obtenedor de datos ) tenemos que declararlo, y tenemos dos formas de hacerlo.

La primera es declararlo en nuestro componente

@Component({
  selector: 'ticket-component',
  template: `
    <h2>Tickets:</h2>
    <ticket *ngFor="let t of tickets" [ticket]="t"></ticket>
  `,
  providers: [TicketsMockUp]
})

Y la segunda opción es en nuestro ngModule:

@NgModule({
  ....
  providers: [TicketsMockUp]
  ....
})

¿Cuál es la diferencia y cuál deberias preferir?

Generalmente, recomiendo registrar proveedores en el nivel de módulo cuando no dependen del DOM, componentes o directivas. Y sólo los proveedores relacionados con la interfaz de usuario que tienen que estar asignados a un componente en particular deben registrarse a nivel de componente. Como `TicketsMockUp` no tiene nada que ver con la interfaz de usuario, deberias registrarla en el nivel del módulo.

Arbol de Inyección

La inyección de dependencias tiene dos partes:

Registro de providers: Cómo y dónde debe crearse un objeto

Inyectar dependencias: De qué depende un objeto.

Y todo lo que un objeto depende (servicios, directivas y elementos) se inyecta en su constructor. Para hacer este trabajo Angular construye un árbol de inyectores.

En primer lugar, cada elemento DOM con un componente o una directiva en él recibe un inyector. Este inyector contiene la instancia de componente, todos los proveedores registrados por el componente y algunos objetos "locales" (por ejemplo, el elemento).

En segundo lugar, al iniciar un `NgModule`, Angular crea un inyector usando el módulo y los proveedores definidos allí.

Así, el árbol inyector de la aplicación se verá así:

O tambien lo podrias ver en el navegador gracias a Augury

(https://augury.angular.io/

Está herramienta para el chrome nos mostrara el arbol de componentes y dependencias que tengamos en nuestra aplicación.

Last updated