Was ist der Unterschied zwischen dem Bereitstellen und Injizieren von "Fenster" und "Fenster" in Winkel 8 und 9?

10

Ich habe zwei Angular-Projekte mit diesen Versionen:

  • 9.0.0-next.6
  • 8.1.0

In der Version 9 habe ich dies verwendet, um das windowObjekt bereitzustellen und zu injizieren :

@NgModule({
  providers: [
    {
      provide: Window,
      useValue: window
    },
  ]
})

export class TestComponent implements OnInit {
  constructor(@Inject(Window) private window: Window)
}

Welches funktioniert gut.


Wenn Sie diesen Ansatz für Version 8 verwenden, werden beim Kompilieren Warnungen und Fehler ausgegeben:

Warnung: Es können nicht alle Parameter für TestComponent aufgelöst werden.

Ich habe es mit einfachen Anführungszeichen wie folgt gelöst:

@NgModule({
  providers: [
    {
      provide: 'Window',
      useValue: window
    },
  ]
})

export class TestComponent implements OnInit {
  constructor(@Inject('Window') private window: Window)
}

Was ist der Unterschied zwischen beiden Versionen?
Was ist der Unterschied in Winkel 8 und 9, der dieses Ding verursacht?

Lampenschirm
quelle
Ich hoffe, dass ich mit dem Kopfgeld eine Antwort bekommen kann, von der ich und andere besser lernen und verstehen können, wie Anbieter und Di in Angular und in verschiedenen Versionen des Frameworks funktionieren.
Lampenschirm

Antworten:

6

Damit Ihre App mit Server Side Rendering funktioniert, empfehlen wir Ihnen, nicht nur Windows Through Token zu verwenden, sondern dieses Token auch SSR-freundlich zu erstellen, ohne darauf zu verweisen window. Angular verfügt über ein integriertes DOCUMENTToken für den Zugriff document. Folgendes habe ich für meine Projekte entwickelt, die windowüber Token verwendet werden können:

import {DOCUMENT} from '@angular/common';
import {inject, InjectionToken} from '@angular/core';

export const WINDOW = new InjectionToken<Window>(
    'An abstraction over global window object',
    {
        factory: () => {
            const {defaultView} = inject(DOCUMENT);

            if (!defaultView) {
                throw new Error('Window is not available');
            }

            return defaultView;
        },
    },
);
Wasserplädoyer
quelle
Ich danke Ihnen sehr für Ihre Antwort. Es ist sehr hilfreich und ich werde in Zukunft eine solche Lösung verwenden.
Lampenschirm
5

Betrachtet man die ValueProviderSchnittstelle:

export declare interface ValueProvider extends ValueSansProvider {
    /**
     * An injection token. Typically an instance of `Type` or `InjectionToken`, but can be `any`.
     */
    provide: any;
    /**
     * When true, injector returns an array of instances. This is useful to allow multiple
     * providers spread across many files to provide configuration information to a common token.
     */
    multi?: boolean;
}

Die provideEigenschaft ist vom Typ any. Das bedeutet, dass jedes Objekt (einschließlich des WindowKonstruktors) darin enthalten sein kann. Das Objekt spielt eigentlich keine Rolle, nur die Referenz spielt eine Rolle, um zu identifizieren, welcher Anbieter zum Einfügen eines Parameters in einen Konstruktor verwendet werden soll.

Es sollte nicht als bewährte Methode angesehen werden, den nativen WindowKonstruktor als Injektionstoken zu verwenden. Es schlägt zur Kompilierungszeit fehl, da Windowes zur Laufzeit in einer Browserumgebung vorhanden ist. Es ist auch als TypeScript vorhanden. declareDer Angular 8-Compiler kann jedoch keine statische Code-Analyse durchführen, um die Parameter Windowin den Anbietern und Windowin einem Konstruktor zu korrelieren , da die Zuweisung von Windowerfolgt vom Browser, nicht vom Code. Ich bin mir nicht sicher, warum es in Angular 9 funktioniert ...

Sie sollten Ihr eigenes Injection-Token erstellen, das den Abhängigkeitsanbieter darstellt. Dieser Injektionstoken sollte entweder:

  • Eine dedizierte Zeichenfolge (wie Sie es getan haben 'Window')
  • Ein engagierter InjectionToken. Zum Beispielexport const window = new InjectionToken<Window>('window');

Darüber hinaus sollte der Winkel Code plattformunabhängig sein (sollte auch in einem Browser und auf einem Node.js Server ausführbar sein) , so wäre es besser, eine Fabrik zu verwenden , dass die Rendite windowoder undefined/ null, dann behandeln Sie das undefined/ nullFall in den Komponenten.

Guerric P.
quelle
1
Vielen Dank für Ihre ausführliche Antwort. Es hat sehr geholfen.
Lampenschirm
1
Sehr gut! Vielen Dank. Ich habe gerade die Angular-Dokumente (v8 und v9) überprüft und kein einziges Beispiel gefunden, in dem Zeichenfolgen verwendet werden. :( Sie sollten dies wirklich in den Dokumenten erklären!
Zaphoid