web-dev-qa-db-de.com

Winkel 6: HTTP_INTERCEPTORS für 'root' angeben

Mit der Änderung von Angular 5, wo Sie einen Dienst in AppModule bereitstellen, in Angular 6, wo Sie den Schlüssel "Bereitstellen" im @Injectable-Dekorator festlegen, habe ich alle Dienste geändert, um die neue Methode "Bereitstellen" zu verwenden. Ausnahme ist jedoch mein Interceptor Service.

Wie kann ich das HTTP_INTERCEPTORS-Token für "root" bereitstellen und InterceptorService verwenden?

dies ist die Angular 5-Methode, mit der ich atm benutze:

@Injectable()
export class InterceptorService implements HttpInterceptor {
...
}

in AppModule:

providers: [{
  provide: HTTP_INTERCEPTORS,
  useClass: InterceptorService,
  multi: true
}]

Aber was wäre Angular 6 Weg?

Ich habe so etwas ausprobiert

@Injectable({
  provideIn: 'root',
  useValue: HTTP_INTERCEPTORS,
  deps: [forwardRef(() => InterceptorService)]
})
export class InterceptorService implements HttpInterceptor {
...
}

und viele andere Varianten mit Injectable, scheinen jedoch nicht herauszufinden, wie sie funktionieren können, ohne ein Objektliteral direkt in die Anbieter eines Moduls zu schreiben.

6
Miloš Tomšik

Die provideIn- -Eigenschaft von Angular 6 ist nur eine Ergänzung des Verhaltens in Angular 5. Wenn Sie etwas mit einem bereits vorhandenen InjectionToken versehen möchten, müssen Sie dennoch die { provide: ClassA, useClass: ClassB }-Syntax verwenden.

Siehe -> https://angular.io/guide/dependency-injection-in-action#external-module-configuration

tl; dr: Die Art und Weise, wie Sie HTTP_INTERCEPTORS angeben, hat sich in Angular 6 nicht geändert, und es gibt keinen "Angular 6" - Weg.

4
Leon

In Interceptor

@Injectable()
export class InterceptorService implements HttpInterceptor {
...
}

Im App-Modul

providers: [{
  provide: HTTP_INTERCEPTORS,
  useClass: InterceptorService,
  multi: true
}]

"Bereitgestellt in ... teilt Angular mit, dass der Root-Injektor für die Erstellung einer Instanz des [Dienstes] verantwortlich ist. Dienste, die auf diese Weise bereitgestellt werden, werden der gesamten Anwendung automatisch zur Verfügung gestellt und müssen nicht sein. in einem beliebigen Modul aufgeführt. "

"Wenn im @Injectable-Dekorator des -Dienstes kein Provider konfiguriert werden kann, registrieren Sie anwendungsweite Provider im Root-AppModule, nicht In der AppComponent. Registrieren Sie im Allgemeinen Provider im NgModule statt im> Root-Anwendungskomponente. "

Wenn der Umfang des Dienstes auf eine Funktion oder einen Zweig der Anwendung beschränkt sein soll, stellen Sie diesen Dienst auf der obersten Komponente für diesen Zweig/diese Funktion bereit

https://angular.io/guide/dependency-injection-in-action

1
Ian Flynn

Hier ein paar Dinge zu beachten:

1. providedIn: 'root' ist eine nette Funktion, die aber wahrscheinlich nicht für Sie erstellt wurde

Wie von @Leon erwähnt, soll diese Funktion dazu führen, dass Dienste baumschonender werden. Es ist nicht dazu gedacht, die providers: []-Eigenschaft eines Moduls vollständig zu ersetzen. Diese Option ist hauptsächlich für Bibliotheksentwickler gedacht, nicht so sehr für Anwendungsentwickler.

Stellen Sie sich dieses Szenario vor:

Sie haben vor einigen Monaten einen Dienst erstellt, der jetzt von Ihrer App nicht mehr verwendet wird. Sie wissen, es wird nicht verwendet, weil es Ihre App ist und Sie die Codebase vollständig kennen und kontrollieren können. Was machst du mit diesem Dienst?

A) Stellen Sie sicher, dass providedIn: 'root' verwendet wird, damit Angular es aus dem Bundle herausschütteln kann, da Sie es nicht mehr verwenden

B) Löschen Sie den Dienst.

Meine Vermutung ist B!

Stellen Sie sich ein anderes Szenario vor:

Sie verwenden ein Angular-Modul eines Drittanbieters aus einem npm-Paket. Dieses Modul verfügt über 12 verschiedene Services, die Sie in Ihrer App verwenden können, um die Funktionen dieser App zu nutzen. Ihre App benötigt nicht alle diese Funktionen, so dass Sie nur drei dieser Servicetypen in Ihre Anwendungskomponenten oder -dienste einfügen.

Wie lösen Sie das?

A) Fassen Sie das Repository so zusammen, dass Sie alle Dienste entfernen können, die Ihre App nicht verwendet, sodass Sie sie nicht in Ihr Bundle aufnehmen müssen.

B) Bitten Sie den Projektbesitzer, providedIn: 'root' zu verwenden. Wenn der Bibliotheksautor providedIn: 'root' verwendet, wirken sich die nicht verwendeten Dienste nicht auf die Paketgröße aus, und sie können im npm-Paket/Angular-Modul verbleiben, damit sie von anderen Teams verwendet werden können, wenn sie diese benötigen.

Meine Vermutung ist B!

2. providedIn: 'root' funktioniert nicht für Interceptors

Interceptors sind ein multi DI-Token-Service, dh Sie können mehrere Werte für dasselbe DI-Token angeben. Dieses Token ist HTTP_INTERCEPTORS. Der @Injectable({...})-Dekorator zeigt keine API für die Bereitstellung des dekorierten Typs für ein anderes Token an, wie dies der @NgModule({...})-Dekorateur tut.

Dies bedeutet, dass Sie Angular Anywhere you would normally ask for 'HTTP_INTERCEPTORS' add this service to the set of values to use instead nicht mit dem @Injectable({...})-Dekorator erkennen können.

Sie können dies nur in einem @NgModule({...}) Dekorateur tun.

3. Die Bereitstellung von Abfangjägern ist auftragsabhängig

Interceptors sind eine Pipeline und die Reihenfolge, in der sie zur Bestimmung der Reihenfolge angegeben werden, in der sie Zugriff auf das Anforderungsobjekt (zum Ändern oder Prüfen) und das Antwortobjekt (zum Ändern oder Prüfen) erhalten.

Während einige Interzeptoren ordnungsunabhängig sein könnten, möchten Sie wahrscheinlich dennoch einen gewissen Determinismus in dieser Reihenfolge.

Selbst wenn providedIn: 'root' für Abfangjäger funktioniert hat, wird die Reihenfolge, in der sie bereitgestellt werden, durch die Auflösungsreihenfolge der Typen während des Angular-Kompilierungsschritts bestimmt - wahrscheinlich nicht das, was Sie möchten.

Wenn Sie sie stattdessen im providers: []-Array in einem @NgModule({...})-Dekorator angeben, können Sie die Reihenfolge explizit festlegen, in der sie aufgerufen werden.

0
seangwright