В чем разница между предоставлением и введением Window в сравнении с Window в Angular 8 и 9?

10

У меня есть два проекта Angular, использующих эти версии:

  • 9.0.0-next.6
  • 8.1.0

В версии 9 я использовал это, чтобы предоставить и ввести windowобъект:

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

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

Который работает отлично.


Принятие этого подхода к версии 8 выдало предупреждения и ошибки во время компиляции:

Предупреждение: не удается разрешить все параметры для TestComponent…

Я решил это с помощью одинарных кавычек, например:

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

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

В чем разница между обеими версиями?
Какая разница в угловых 8 и 9, что вызывает эту вещь?

абажур
источник
Я надеюсь , что с щедростью я могу получить ответ , из которого я и других может узнать и лучше понять , как поставщик и ди в угловом и в разных версиях рамочной работы.
абажур

Ответы:

6

Для того чтобы ваше приложение работало с рендерингом на стороне сервера, я предлагаю вам не только использовать окно через токен, но и создавать этот токен дружественным по отношению к SSR способом, windowвообще не ссылаясь на него. Angular имеет встроенный DOCUMENTтокен для доступа document. Вот что я придумал, чтобы мои проекты использовали windowчерез токены:

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
источник
Большое спасибо за ваш ответ. Это очень полезно, и я собираюсь использовать подобное решение в будущем.
абажур
5

Учитывая 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;
}

provideСвойство типа any. Это означает, что любой объект (включая Windowконструктор) может войти внутрь него. Объект на самом деле не имеет значения, важна только ссылка, чтобы определить, какой поставщик должен использоваться для вставки параметра в конструктор.

Не следует считать хорошей практикой использование собственного Windowконструктора в качестве токена внедрения. Он не выполняется во время компиляции, поскольку Windowсуществует во время выполнения в среде браузера, он также существует в виде TypeScript, declareно компилятор Angular 8 не может выполнять статический анализ кода для сопоставления параметров Windowв поставщиках и Windowв конструкторе, поскольку назначениеWindow сделано браузером, а не кодом. Не уверен, почему это работает в Angular 9, хотя ...

Вы должны создать свой собственный токен инъекции, который представляет поставщика зависимостей. Этот токен инъекции должен быть:

  • Выделенная строка (как вы сделали с 'Window')
  • Посвященный InjectionToken. Напримерexport const window = new InjectionToken<Window>('window');

Более того, код Angular должен быть независимым от платформы (должен выполняться в браузере и на сервере Node.js), поэтому было бы лучше использовать фабрику, которая возвращает windowили undefined/ null, а затем обрабатывать undefined/ nullcase в компонентах.

Геррик П
источник
1
Большое спасибо за ваш подробный ответ. Это очень помогло.
абажур
1
Отлично! Спасибо. Я только что проверил документы Angular (v8 и v9), и я не нашел ни одного примера, где бы они использовали строки. :( Они должны действительно объяснить это в документах!
Zaphoid