Qual é a diferença entre fornecer e injetar 'Window' vs Window no Angular 8 e 9?

10

Eu tenho dois projetos Angular usando estas versões:

  • 9.0.0-next.6
  • 8.1.0

Na versão 9, usei isso para fornecer e injetar o windowobjeto:

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

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

O que funciona bem.


A adoção dessa abordagem para a versão 8 gerou avisos e erros durante a compilação:

Aviso: Não é possível resolver todos os parâmetros do TestComponent…

Eu o resolvi usando aspas simples, assim:

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

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

Qual é a diferença entre as duas versões?
Qual é a diferença nos angulares 8 e 9 que causa isso?

abajur
fonte
Espero que, com a recompensa, eu possa obter uma resposta da qual eu e outros possamos aprender e entender melhor como os provedores e di Angular e em diferentes versões da estrutura funcionam.
abajur

Respostas:

6

Para que seu aplicativo funcione com a renderização no lado do servidor, sugiro que você não apenas use a janela por meio de token, mas também crie esse token de maneira amigável ao SSR, sem fazer nenhuma referência window. Angular possui um DOCUMENTtoken interno para acessar document. Aqui está o que eu criei para meus projetos usarem windowatravés de tokens:

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
fonte
Muito obrigado pela sua resposta. É muito útil e vou usar uma solução como essa no futuro.
abajur
5

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

A providepropriedade é do tipo any. Isso significa que qualquer objeto (incluindo o Windowconstrutor) pode entrar nele. O objeto realmente não importa, apenas a referência importa para identificar qual provedor deve ser usado para injetar um parâmetro em um construtor.

Não deve ser considerado uma boa prática usar o Windowconstrutor nativo como um token de injeção. Ele falha no tempo de compilação porque Windowexiste no tempo de execução em um ambiente de navegador, também existe como um TypeScript, declaremas o compilador Angular 8 não pode fazer análise de código estático para correlacionar os parâmetros Windownos provedores e Windownos construtores, uma vez que a atribuição de Windowé feita pelo navegador, não pelo código. Não sei por que funciona no Angular 9, no entanto ...

Você deve criar seu próprio token de injeção que representa o provedor de dependência. Esse token de injeção deve ser:

  • Uma string dedicada (como você fez com 'Window')
  • Um dedicado InjectionToken. Por exemploexport const window = new InjectionToken<Window>('window');

Além disso, o código angular deve ser independente de plataforma (deve ser executável em um navegador e também em um servidor Node.js.), portanto, seria melhor usar uma fábrica que retorne windowou undefined/ e null, em seguida, manipule o undefined/ nullcase nos componentes.

Guerric P
fonte
11
Muito obrigado pela sua resposta detalhada. Ele ajudou muito.
abajur
11
Muito bom! Obrigado. Acabei de verificar os documentos angulares (v8 e v9) e não encontrei um único exemplo em que eles usem cadeias de caracteres. :( Eles realmente devem explicar isso nos documentos!
Zaphoid 12/02