ข้อแตกต่างระหว่างการให้และการฉีด 'Window' กับ Window ใน Angular 8 และ 9 คืออะไร


10

ฉันมีโครงการสองแองกูลาร์ที่ใช้เวอร์ชันเหล่านี้:

  • 9.0.0-next.6
  • 8.1.0

ในรุ่น 9 ฉันใช้สิ่งนี้เพื่อจัดเตรียมและฉีดwindowobhject:

@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)
}

ความแตกต่างระหว่างทั้งสองรุ่นคืออะไร?
อะไรคือความแตกต่างของ Angular 8 และ 9 ที่ทำให้เกิดสิ่งนี้


ฉันหวังว่าด้วยความกรุณาฉันจะได้รับคำตอบจากสิ่งที่ฉันและคนอื่น ๆ สามารถเรียนรู้และเข้าใจได้ดียิ่งขึ้นว่าผู้ให้บริการและดิจิตัลใน Angular และกรอบงานรุ่นต่าง ๆ ทำงานอย่างไร
โป๊ะ

คำตอบ:


6

เพื่อให้แอปของคุณทำงานกับการแสดงผลฝั่งเซิร์ฟเวอร์ฉันไม่แนะนำให้คุณใช้หน้าต่างผ่านโทเค็นเท่านั้น แต่ยังสร้างโทเค็นนี้ในลักษณะที่เป็นมิตรกับ SSR โดยไม่ต้องอ้างอิง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สร้าง) สามารถเข้าไปด้านในได้ จริง ๆ แล้ววัตถุไม่สำคัญเฉพาะการอ้างอิงเท่านั้นที่จะระบุว่าผู้ให้บริการรายใดที่ควรใช้ในการฉีดพารามิเตอร์ใน Constructor

ไม่ควรถือว่าเป็นการปฏิบัติที่ดีที่จะใช้ตัวWindowสร้างดั้งเดิมเป็นโทเค็นการฉีด มันล้มเหลวที่รวบรวมเวลาเพราะWindowมีอยู่ในเวลาทำงานในสภาพแวดล้อมของเบราว์เซอร์ก็ยังอยู่ในฐานะ typescript declareแต่เชิงมุม 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 docs (v8 และ v9) และฉันไม่พบตัวอย่างเดียวที่พวกเขาใช้สตริง :( พวกเขาควรอธิบายสิ่งนี้ในเอกสาร!
Zaphoid
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.