Wer schon etwas länger im Team “Angular” spielt, wird sich noch daran erinnern, dass zu früheren Tagen alle Services im “providers” Array des Moduls deklariert werden mussten. Dank globaler Deklaration via providedIn: ‘root’ ist das zum Glück nicht mehr notwendig. Hier und da ist es dennoch erforderlich, in die DI von Angular einzugreifen und explizite Provider zu deklarieren. So werden viele Bibliotheken über entsprechende Injection-Token konfiguriert oder HTTP-Interceptoren und Error-Handler registriert.
Eine weitere Möglichkeit ist die Bereitstellungen von mehreren unterschiedlichen Serviceinstanzen, um z.B. auf Modul-Ebene eigene Instanzen zu haben oder über einen Injection-Token unterschiedliche Anwendungs-Fälle zu unterscheiden. Ein schönes Beispiel ist Folgendes:
Mehrere fachliche Komponenten (Benutzer-, Kunde-, Lieferant-Übersicht) nutzen alle dieselbe generische Komponente, die z.B. ein Suchformular und eine Tabellendarstellung realisiert, die wiederum einen Service verwendet. Dieser Service ist je nach fachlichem Kontext unterschiedlich. Anstatt nun allen generischen Komponenten eine Service-Instanz per PropertyBinding zu übergeben, können wir auf den fachlichen Komponenten einen Provider deklarieren:
providers: [
{provide: DemoService, useClass: DemoService}
]
der dazu führt, dass alle Kind-Komponenten in der gesamten folgenden Hierarchie sich diese (eigene) Instanz teilen.
Nachteil: diese Service-Instanz wird bei OnDestroy der fachlichen Komponente ebenfalls zerstört. Was ggf. völlig in Ordnung sein kann, nicht, aber wenn wir z.B. die alten Eingaben der Suche erhalten wollen. Abhilfe schafft hier nun die Deklaration von individuellen Services (via InjectionToken) auf Modul-Ebene
providers: [
{provide: TOKEN_A, useClass: DemoService},
{provide: TOKEN_B, useClass: DemoService},
]
die wiederum in den fachlichen Komponenten via providers für den Typ des Services eingesetzt werden
@Component({
selector: 'app-acomponent',
...
providers: [
{provide: DemoService, useFactory: (injector: Injector) => injector.get(TOKEN_A), deps: [Injector]},
]
})
---
@Component({
selector: 'app-bcomponent',
...
providers: [
{provide: DemoService, useFactory: (injector: Injector) => injector.get(TOKEN_B), deps: [Injector]}
]
})
sodass die generischen Komponenten, gar nicht mitbekommen, welche fachliche Ausprägung des Services sie bekommen und ihren Service wie immer über den Konstruktor konsumieren:
@Component({
selector: 'app-generic-sub',
...
})
export class GenericSubComponent {
constructor(public demoService: DemoService) {
}
}