Apa perbedaan antara menyediakan dan menyuntikkan 'Jendela' vs Jendela di Angular 8 dan 9?

10

Saya memiliki dua proyek Angular menggunakan versi ini:

  • 9.0.0-next.6
  • 8.1.0

Dalam versi 9 saya menggunakan ini untuk menyediakan dan menyuntikkan windowobjek:

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

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

Itu bekerja dengan baik.


Mengambil pendekatan ini untuk versi 8 melemparkan peringatan dan kesalahan selama kompilasi:

Peringatan: Tidak dapat menyelesaikan semua parameter untuk TestComponent ...

Saya menyelesaikannya dengan menggunakan tanda kutip tunggal, seperti ini:

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

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

Apa perbedaan antara kedua versi?
Apa perbedaan dalam Angular 8 dan 9 yang menyebabkan hal ini?

kap lampu
sumber
Saya berharap dengan karunia saya bisa mendapatkan jawaban dari mana saya dan orang lain dapat belajar dan memahami lebih baik bagaimana penyedia dan di di Angular dan dalam versi yang berbeda dari kerangka kerja bekerja.
kap lampu

Jawaban:

6

Agar aplikasi Anda berfungsi dengan Server Side Rendering, saya sarankan Anda tidak hanya menggunakan jendela melalui token, tetapi juga membuat token ini dengan cara yang ramah SSR, tanpa referensi windowsama sekali. Angular memiliki DOCUMENTtoken bawaan untuk mengakses document. Inilah yang saya buat untuk proyek saya untuk digunakan windowmelalui token:

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;
        },
    },
);
semangka
sumber
Terimakasih banyak atas jawaban Anda. Ini sangat membantu dan saya akan menggunakan solusi seperti ini di masa depan.
kap lampu
5

Mempertimbangkan ValueProviderantarmuka:

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

The provideproperti adalah tipe any. Itu berarti benda apa pun (termasuk Windowkonstruktor) dapat masuk ke dalamnya. Objek sebenarnya tidak masalah, hanya referensi masalah untuk mengidentifikasi penyedia mana yang harus digunakan untuk menyuntikkan parameter dalam konstruktor.

Seharusnya tidak dianggap sebagai praktik yang baik untuk menggunakan Windowkonstruktor asli sebagai token injeksi. Gagal pada waktu kompilasi karena Windowada pada saat dijalankan dalam lingkungan browser, ia juga ada sebagai TypeScript declaretetapi kompiler Angular 8 tidak dapat melakukan analisis kode statis untuk mengkorelasikan Windowdalam penyedia dan Windowdalam parameter konstruktor, karena penugasan dariWindow dilakukan oleh browser, bukan oleh kode. Tidak yakin mengapa ini bekerja di Angular 9, ...

Anda harus membuat token injeksi Anda sendiri yang mewakili penyedia ketergantungan. Token injeksi ini harus berupa:

  • String khusus (seperti yang Anda lakukan dengan 'Window')
  • Berdedikasi InjectionToken. Sebagai contohexport const window = new InjectionToken<Window>('window');

Selain itu, kode Angular harus platform agnostik (harus dapat dieksekusi di browser dan pada server Node.js juga) sehingga akan lebih baik menggunakan pabrik yang mengembalikan windowatau undefined/ null, kemudian menangani undefined/ nullcase dalam komponen.

Guerric P
sumber
1
Terima kasih banyak atas jawaban terinci Anda. Itu banyak membantu.
kap lampu
1
Baik sekali! Terima kasih. Saya baru saja memeriksa dokumen Angular (v8 dan v9) dan saya tidak menemukan satu pun contoh di mana mereka menggunakan string. :( Mereka harus benar-benar menjelaskan hal ini di dokumen!
Zaphoid