Яка різниця між наданням та ін'єкцією "Window" проти Window у кутовій 8 та 9?


10

У мене є два кутові проекти, які використовують такі версії:

  • 9.0.0-наступний.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, що викликає цю річ?


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

Відповіді:


6

Для того, щоб ваша програма працювала з серверним рендерінгом, я пропоную вам не тільки використовувати вікно через маркер, але і створити цей маркер в дружньому вигляді, не посилаючись windowна це. Кутовий має вбудований 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;
        },
    },
);

Дуже дякую за вашу відповідь. Це дуже корисно, і я буду використовувати таке рішення в майбутньому.
абажур

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виконується через браузер, а не за кодом. Не впевнений, чому він працює в куті 9, хоча ...

Ви повинні створити власний маркер ін'єкції, який представляє постачальника залежностей. Цей маркер для ін'єкцій має бути або:

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

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


1
Дуже дякую за детальну відповідь. Це дуже допомогло.
абажур

1
Дуже добре! Дякую. Я щойно перевірив кутові документи (v8 та v9) і не знайшов жодного прикладу, де вони використовують рядки. :( Вони справді повинні пояснити це в документах!
Зафоїд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.