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