Jaka jest różnica między dostarczaniem i wstrzykiwaniem „Window” a Window w Angular 8 i 9?

10

Mam dwa projekty Angular wykorzystujące te wersje:

  • 9.0.0-next.6
  • 8.1.0

W wersji 9 użyłem tego, aby dostarczyć i wstrzyknąć windowobiekt:

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

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

Które działa dobrze.


Takie podejście do wersji 8 generowało ostrzeżenia i błędy podczas kompilacji:

Ostrzeżenie: nie można rozwiązać wszystkich parametrów TestComponent…

Rozwiązałem to za pomocą pojedynczych cudzysłowów, takich jak to:

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

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

Jaka jest różnica między obiema wersjami?
Jaka jest różnica w Angular 8 i 9, która powoduje to?

abażur
źródło
Mam nadzieję, że z dobroci mogę uzyskać odpowiedź, z której mogę i inne nauki i lepszego zrozumienia, jak dostawców i di kątowej iw różnych wersjach pracy ramowej.
abażur

Odpowiedzi:

6

Aby Twoja aplikacja działała z renderowaniem po stronie serwera, sugeruję nie tylko używanie okna przez token, ale także tworzenie tego tokena w sposób przyjazny dla SSR, bez odwoływania się windoww ogóle. Angular ma wbudowany DOCUMENTtoken dostępu document. Oto, co wymyśliłem, aby moje projekty mogły używać windowza pomocą tokenów:

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;
        },
    },
);
waterplea
źródło
Bardzo dziękuję za odpowiedź. Jest to bardzo pomocne i zamierzam użyć takiego rozwiązania w przyszłości.
abażur
5

Biorąc pod uwagę ValueProviderinterfejs:

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;
}

provideNieruchomość jest typu any. Oznacza to, że dowolny obiekt (włącznie z Windowkonstruktorem) może wejść do niego. Obiekt w rzeczywistości nie ma znaczenia, tylko odniesienia mają znaczenie w celu ustalenia, który dostawca powinien zostać użyty do wstrzyknięcia parametru do konstruktora.

Nie należy uważać za dobrą praktykę używania natywnego Windowkonstruktora jako tokena wstrzykiwania. Nie powiedzie się w czasie kompilacji, ponieważ Windowistnieje w czasie wykonywania w środowisku przeglądarki, istnieje również jako TypeScript, declareale kompilator Angular 8 nie może przeprowadzić analizy kodu statycznego w celu skorelowania Windowparametrów dostawców i Windowkonstruktora, ponieważ przypisanie Windowjest wykonane przez przeglądarkę, a nie przez kod. Nie jestem pewien, dlaczego działa w Angular 9, chociaż ...

Należy utworzyć własny token wstrzykiwania, który reprezentuje dostawcę zależności. Ten token wtrysku powinien być:

  • Dedykowany ciąg (jak to zrobiłeś 'Window')
  • Dedykowany InjectionToken. Na przykładexport const window = new InjectionToken<Window>('window');

Ponadto kod Angular powinien być niezależny od platformy (powinien być wykonywalny w przeglądarce i na serwerze Node.js), więc lepiej byłoby użyć fabryki, która zwraca windowlub undefined/ null, a następnie obsługiwać undefined/ nullcase w komponentach.

Guerric P
źródło
1
Dziękuję bardzo za szczegółową odpowiedź. To bardzo pomogło.
abażur
1
Bardzo dobre! Dzięki. Właśnie sprawdziłem dokumentację Angular (v8 i v9) i nie znalazłem ani jednego przykładu, w którym używają ciągów. :( Naprawdę powinni to wyjaśnić w dokumentacji!
Zaphoid