J'ai deux projets Angular utilisant ces versions:
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?
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;
},
},
);
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:
'Window'
)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.