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


10

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' windowobjet:

@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 entre Angular 8 et 9 qui cause cette chose?


J'espère qu'avec la générosité, je pourrai obtenir une réponse à partir de laquelle moi et d'autres pouvons apprendre et mieux comprendre comment fonctionnent les fournisseurs et di dans Angular et dans différentes versions du cadre.
abat

Réponses:


6

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 windowdu tout. Angular a un DOCUMENTjeton intégré pour accéder document. Voici ce que j'ai trouvé pour mes projets à utiliser windowvia 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;
        },
    },
);

Merci beaucoup pour votre réponse. C'est très utile et je vais utiliser une solution comme celle-ci à l'avenir.
abat

5

Considérant l' ValueProviderinterface:

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 providepropriété est de type any. Cela signifie que tout objet (y compris le Windowconstructeur) peut y pénétrer. L'objet n'a en fait pas d'importance, seule la référence compte 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 Windowconstructeur natif comme jeton d'injection. Il échoue au moment de la compilation, car il Windowexiste au moment de l'exécution dans un environnement de navigateur, il existe également en tant que TypeScript, declaremais le compilateur Angular 8 ne peut pas faire d'analyse de code statique pour corréler les paramètres Windowdans les fournisseurs et Windowdans les paramètres du constructeur, car l'affectation de Windowest effectuée par le navigateur, pas par le code. Je ne sais pas 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:

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

De plus, le code 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 usine qui renvoie windowou undefined/ null, puis de gérer le undefined/ nullcase dans les composants.


1
Merci beaucoup pour votre réponse détaillée. Cela a beaucoup aidé.
abat

1
Très bien! Merci. Je viens de vérifier les documents Angular (v8 et v9) et je n'ai pas trouvé un seul exemple où ils utilisent des chaînes. :( Ils devraient vraiment expliquer cela dans les documents!
Zaphoid
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.