Drzewo wstrzykiwania

W Angular 1.x był tylko jeden iniektor i wszystkie usługi były singletons. W Angular 2+ jest conajmniej jeden wstrzykiwacz na aplikację. Są one zorganizowane w drzewie, które jest równoległe do drzewa komponentów Angular.

Rozważ następujące drzewo, które modeluje aplikację czatu składającą się z dwóch
otwartych okien czatu i widżetu logowania/wylogowania.Obraz drzewa komponentów i drzewa DI

Na powyższym obrazku znajduje się jeden wstrzykiwacz główny, który jest ustanowiony przez
listę provider@NgModule. We wstrzykiwaczu Root rejestrowany jest LoginService.

Pod głównym wstrzykiwaczem znajduje się główny komponent (Root Windows Component). Nie ma on tablicy provider i użyje wstrzykiwacza root dla wszystkich swoich zależności.

Istnieją również dwa wstrzykiwanieiwacze dla potomków, po jednym dla każdego komponentu ChatWindow. Każdy z tych komponentów ma własną instancję ChatService.

Istnieje trzeci komponent potomny: Login / Logout, ale nie ma on wstrzykiwacza.

Istnieje kilka elementów wnuka, bez wstrzykiwaczy. Są to ChatFeed iChatInput dla każdego ChatWindow. Istnieje również składniki LoginWidget iLogoutWidget z Logout/Login jako ich rodzicem.

Drzewo wstrzykiwaczy nie tworzy nowego wstrzykiwacza dla każdego modułu, ale dla każdego modułu z tablicą provider w swoim dekoratorze.
Moduły, które nie mają tablicy provider, szukają swojego elementu macierzystego dla wstrzykiwania. Jeśli rodzic nie ma wstrzykiwacza, patrzy w górę, aż dotrze do głównego wstrzykiwacza.

Ostrzeżenie: Uważaj na tablice provider. Jeśli element potomny jest ozdobiony a
tablica provider zawierająca zależności, które także były wymagane w obiekcie nadrzędnym, zależności, które dziecko otrzymuje, będą śledzić zależności rodziców.
Może to mieć różnego rodzaju niezamierzone konsekwencje.

Rozważmy następujący przykład:

  • app/module.ts
const randomFactory = () => { return Math.random(); };
@NgModule({
  imports: [BrowserModule],
  declarations: [
    AppComponent,
    ChildInheritorComponent,
    ChildOwnInjectorComponent,
  ],
  /* Provide dependencies here /
  providers: [Unique],
  bootstrap: [AppComponent],
})
export class AppModule {}

W powyższym przykładzie Unique jest ładowany do wstrzykiwacza głównego.

  • app/services/unique.ts
import { Injectable } from '@angular/core';

@Injectable()
export class Unique {
  value = (+Date.now()).toString(16) + '.' +
    Math.floor(Math.random() * 500);
}

Usługa Unique generuje wartość unikalną dla instancji podczas jej tworzenia.

  • app/components/child-inheritor.component.ts
import { Component, Inject } from '@angular/core';
import { Unique } from '../services/unique';
@Component({
  selector: 'app-child-inheritor',
  template: <span>{{ value }}</span>
})
export class ChildInheritorComponent {
  value = this.u.value;
constructor(private u: Unique) { }
}
  • Dziedziczenie dziecka nie ma wstrzykiwacza. Przemieści on drzewo komponentów w górę, szukając wstrzykiwacza.

* app/components/child-own-injector.component.ts

import { Component, Inject } from '@angular/core';
import { Unique } from '../services/unique';

@Component({
  selector: 'child-own-injector',
  template: `<span>{{ value }}</span>`,
  providers: [Unique]
})
export class ChildOwnInjectorComponent {
  value = this.u.value;

  constructor(private u: Unique) { }
}

Komponent wstrzykiwacza dla dziecka ma wstrzykiwacz, który jest wypełniony swoim własnym wystąpienie Unique. Ten komponent nie będzie udostępniać tej samej wartości co komponent Instancja unikalna wstrzykiwanieiwacza root.

  • app/containers/app.ts

    @Component({
    selector: 'app-root',
    template: `
      <p>
        App's Unique dependency has a value of 
      </p>
      <p>
        which should match
      </p>
      <p>
        ChildInheritor's value:
        <app-child-inheritor></app-child-inheritor>
      </p>
      <p>
        However,
      </p>
      <p>
        ChildOwnInjector should have its own value:
        <app-child-own-injector></app-child-own-injector>
      </p>
      <p>
        ChildOwnInjector's other instance should also have its own value:
        <app-child-own-injector></app-child-own-injector>
      </p>`,
    })
    export class AppComponent {
    value: number = this.u.value;
    
    constructor(private u: Unique) { }
    }
    

    Zobacz przykład: [024]