web-dev-qa-db-fra.com

Quelle est la différence entre fournir et injecter 'Window' vs Window dans Angular 8 and 9?

J'ai deux projets Angular utilisant ces versions:

  • 9.0.0-next.6
  • 8.1.0

Dans la version 9, j'ai utilisé ceci pour fournir et injecter l'objet window:

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

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

Ce qui fonctionne bien.


Cette approche de la version 8 a généré des avertissements et des erreurs lors de la compilation:

Avertissement: impossible de résoudre tous les paramètres de TestComponent…

Je l'ai résolu en utilisant des guillemets simples, comme ceci:

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

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

Quelle est la différence entre les deux versions?
Quelle est la différence dans Angular 8 et 9 qui provoque cette chose?

10
lampshade

Pour que votre application fonctionne avec le rendu côté serveur, je vous suggère non seulement d'utiliser la fenêtre via le jeton, mais également de créer ce jeton de manière conviviale SSR, sans référencer du tout window. Angular a un jeton DOCUMENT intégré pour accéder à document. Voici ce que j'ai trouvé pour que mes projets utilisent window via des jetons:

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;
        },
    },
);
6
waterplea

Considérant l'interface ValueProvider:

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

La propriété provide est de type any. Cela signifie que tout objet (y compris le constructeur Window) peut y entrer. L'objet n'a en fait pas d'importance, seul référence importe pour identifier le fournisseur à utiliser pour injecter un paramètre dans un constructeur.

Il ne doit pas être considéré comme une bonne pratique d'utiliser le constructeur natif Window comme jeton d'injection. Il échoue au moment de la compilation car Window existe au moment de l'exécution dans un environnement de navigateur, il existe également en tant que TypeScript declare mais le compilateur Angular 8 ne peut pas faire de statique analyse de code pour corréler le Window dans les fournisseurs et le Window dans les paramètres d'un constructeur, car l'affectation de Window est effectuée par le navigateur, pas par le code. Pas sûr pourquoi cela fonctionne dans Angular 9, cependant ...

Vous devez créer votre propre jeton d'injection qui représente le fournisseur de dépendances. Ce jeton d'injection doit être soit:

  • Une chaîne dédiée (comme vous l'avez fait avec 'Window')
  • Un InjectionToken dédié. Par exemple export const window = new InjectionToken<Window>('window');

De plus, le code Angular angulaire devrait être indépendant de la plate-forme (devrait également être exécutable dans un navigateur et sur un serveur Node.js), il serait donc préférable d'utiliser une fabrique qui renvoie window ou undefined/null, puis gérez le cas undefined/null dans les composants.

5
Guerric P