Angular 如何将窗口注入服务?

Angular 如何将窗口注入服务?,angular,typescript,dependency-injection,Angular,Typescript,Dependency Injection,我正在用TypeScript编写Angular 2服务,它将使用localstorage。我想在我的服务中插入对浏览器窗口对象的引用,因为我不想引用任何全局变量,如Angular 1.x$window 如何执行此操作?设置提供程序后,您只需注入它即可: import {provide} from 'angular2/core'; bootstrap(..., [provide(Window, {useValue: window})]); constructor(private window:

我正在用TypeScript编写Angular 2服务,它将使用
localstorage
。我想在我的服务中插入对浏览器
窗口
对象的引用,因为我不想引用任何全局变量,如Angular 1.x
$window


如何执行此操作?

设置提供程序后,您只需注入它即可:

import {provide} from 'angular2/core';
bootstrap(..., [provide(Window, {useValue: window})]);

constructor(private window: Window) {
    // this.window
}

您可以在设置提供程序后插入它:

import {provide} from 'angular2/core';
bootstrap(..., [provide(Window, {useValue: window})]);

constructor(private window: Window) {
    // this.window
}
截至今天(2016年4月),前一个解决方案中的代码不起作用,我认为可以将window直接注入App.ts,然后将您需要的值收集到服务中,以便在App中进行全局访问,但如果您更喜欢创建并注入您自己的服务,一种更简单的解决方案是这样的

截至今天(2016年4月),前一个解决方案中的代码不起作用,我认为可以将window直接注入App.ts,然后将您需要的值收集到服务中,以便在App中进行全局访问,但如果您更喜欢创建并注入您自己的服务,一种更简单的解决方案是这样的


我知道问题是如何将窗口对象注入到组件中,但您这样做似乎只是为了访问本地存储。如果您真的只需要本地存储,为什么不使用一个公开本地存储的服务,比如。然后,组件将描述其真正的依赖关系,这使代码更具可读性。

我知道问题是如何将窗口对象注入组件,但您这样做似乎只是为了访问本地存储。如果您真的只需要本地存储,为什么不使用一个公开本地存储的服务,比如。然后,您将描述其真正的依赖关系,这使您的代码更具可读性。

这是我目前的工作(2018-03,angular 5.2,带AoT,在angular cli和自定义网页包构建中测试):

首先,创建一个可注入服务,该服务提供对窗口的引用:

import { Injectable } from '@angular/core';

// This interface is optional, showing how you can add strong typings for custom globals.
// Just use "Window" as the type if you don't have custom global stuff
export interface ICustomWindow extends Window {
    __custom_global_stuff: string;
}

function getWindow (): any {
    return window;
}

@Injectable()
export class WindowRefService {
    get nativeWindow (): ICustomWindow {
        return getWindow();
    }
}
现在,向根AppModule注册该服务,以便可以将其注入任何地方:

import { WindowRefService } from './window-ref.service';

@NgModule({        
  providers: [
    WindowRefService 
  ],
  ...
})
export class AppModule {}
然后在稍后需要注入
窗口的地方:

import { Component} from '@angular/core';
import { WindowRefService, ICustomWindow } from './window-ref.service';

@Component({ ... })
export default class MyCoolComponent {
    private _window: ICustomWindow;

    constructor (
        windowRef: WindowRefService
    ) {
        this._window = windowRef.nativeWindow;
    }

    public doThing (): void {
        let foo = this._window.XMLHttpRequest;
        let bar = this._window.__custom_global_stuff;
    }
...
如果您在应用程序中使用本地文档,您可能还希望以类似的方式向该服务添加
本地文档
和其他全局文档


编辑: 更新了Truchainz建议。 编辑2: 为angular 2.1.2更新 编辑3: 添加了AoT注释 编辑4: 添加
any
类型变通说明 edit5:更新了使用WindowRefService的解决方案,该解决方案修复了我在使用不同版本的上一个解决方案时遇到的错误
edit6:添加示例自定义窗口键入

这目前对我有效(2018-03,angular 5.2,带AoT,在angular cli和自定义网页包构建中测试):

首先,创建一个可注入服务,该服务提供对窗口的引用:

import { Injectable } from '@angular/core';

// This interface is optional, showing how you can add strong typings for custom globals.
// Just use "Window" as the type if you don't have custom global stuff
export interface ICustomWindow extends Window {
    __custom_global_stuff: string;
}

function getWindow (): any {
    return window;
}

@Injectable()
export class WindowRefService {
    get nativeWindow (): ICustomWindow {
        return getWindow();
    }
}
现在,向根AppModule注册该服务,以便可以将其注入任何地方:

import { WindowRefService } from './window-ref.service';

@NgModule({        
  providers: [
    WindowRefService 
  ],
  ...
})
export class AppModule {}
然后在稍后需要注入
窗口的地方:

import { Component} from '@angular/core';
import { WindowRefService, ICustomWindow } from './window-ref.service';

@Component({ ... })
export default class MyCoolComponent {
    private _window: ICustomWindow;

    constructor (
        windowRef: WindowRefService
    ) {
        this._window = windowRef.nativeWindow;
    }

    public doThing (): void {
        let foo = this._window.XMLHttpRequest;
        let bar = this._window.__custom_global_stuff;
    }
...
如果您在应用程序中使用本地文档,您可能还希望以类似的方式向该服务添加
本地文档
和其他全局文档


编辑: 更新了Truchainz建议。 编辑2: 为angular 2.1.2更新 编辑3: 添加了AoT注释 编辑4: 添加
any
类型变通说明 edit5:更新了使用WindowRefService的解决方案,该解决方案修复了我在使用不同版本的上一个解决方案时遇到的错误
edit6:随着angular 2.0.0-rc.5模块的发布,添加了自定义窗口键入的示例。以前的解决方案对我不起作用。这就是我为修复它所做的:

app.module.ts:

@NgModule({        
  providers: [
    { provide: 'Window',  useValue: window }
  ],
  declarations: [...],
  imports: [...]
})
export class AppModule {}
在某些组件中:

import { Component, Inject } from '@angular/core';

@Component({...})
export class MyComponent {
    constructor (@Inject('Window') window: Window) {}
}
您还可以使用一个而不是字符串“Window”

编辑:

AppModule用于在main.ts中引导应用程序,如下所示:

import { platformBrowserDynamic  } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';

platformBrowserDynamic().bootstrapModule(AppModule)

有关NgModule的更多信息,请阅读Angular 2文档:

随着Angular 2.0.0-rc的发布,NgModule的推出。以前的解决方案对我不起作用。这就是我为修复它所做的:

app.module.ts:

@NgModule({        
  providers: [
    { provide: 'Window',  useValue: window }
  ],
  declarations: [...],
  imports: [...]
})
export class AppModule {}
在某些组件中:

import { Component, Inject } from '@angular/core';

@Component({...})
export class MyComponent {
    constructor (@Inject('Window') window: Window) {}
}
您还可以使用一个而不是字符串“Window”

编辑:

AppModule用于在main.ts中引导应用程序,如下所示:

import { platformBrowserDynamic  } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';

platformBrowserDynamic().bootstrapModule(AppModule)
有关NgModule的更多信息,请阅读Angular 2文档:

我用于“窗口”字符串:

import {unimplemented} from '@angular/core/src/facade/exceptions';
import {OpaqueToken, Provider} from '@angular/core/index';

function _window(): any {
    return window;
}

export const WINDOW: OpaqueToken = new OpaqueToken('WindowToken');

export abstract class WindowRef {
    get nativeWindow(): any {
        return unimplemented();
    }
}

export class BrowserWindowRef extends WindowRef {
    constructor() {
        super();
    }
    get nativeWindow(): any {
        return _window();
    }
}


export const WINDOW_PROVIDERS = [
    new Provider(WindowRef, { useClass: BrowserWindowRef }),
    new Provider(WINDOW, { useFactory: _window, deps: [] }),
];
并且仅用于在Angular 2.0.0-rc-4中的引导中导入
窗口提供程序

但是随着Angular 2.0.0-rc.5的发布,我需要创建一个单独的模块:

import { NgModule } from '@angular/core';
import { WINDOW_PROVIDERS } from './window';

@NgModule({
    providers: [WINDOW_PROVIDERS]
})
export class WindowModule { }
刚刚在我的main
app.module.ts的imports属性中定义

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { WindowModule } from './other/window.module';

import { AppComponent } from './app.component';

@NgModule({
    imports: [ BrowserModule, WindowModule ],
    declarations: [ ... ],
    providers: [ ... ],
    bootstrap: [ AppComponent ]
})
export class AppModule {}
我用于“窗口”字符串:

import {unimplemented} from '@angular/core/src/facade/exceptions';
import {OpaqueToken, Provider} from '@angular/core/index';

function _window(): any {
    return window;
}

export const WINDOW: OpaqueToken = new OpaqueToken('WindowToken');

export abstract class WindowRef {
    get nativeWindow(): any {
        return unimplemented();
    }
}

export class BrowserWindowRef extends WindowRef {
    constructor() {
        super();
    }
    get nativeWindow(): any {
        return _window();
    }
}


export const WINDOW_PROVIDERS = [
    new Provider(WindowRef, { useClass: BrowserWindowRef }),
    new Provider(WINDOW, { useFactory: _window, deps: [] }),
];
并且仅用于在Angular 2.0.0-rc-4中的引导中导入
窗口提供程序

但是随着Angular 2.0.0-rc.5的发布,我需要创建一个单独的模块:

import { NgModule } from '@angular/core';
import { WINDOW_PROVIDERS } from './window';

@NgModule({
    providers: [WINDOW_PROVIDERS]
})
export class WindowModule { }
刚刚在我的main
app.module.ts的imports属性中定义

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { WindowModule } from './other/window.module';

import { AppComponent } from './app.component';

@NgModule({
    imports: [ BrowserModule, WindowModule ],
    declarations: [ ... ],
    providers: [ ... ],
    bootstrap: [ AppComponent ]
})
export class AppModule {}

在Angular RC4中,以下是上述一些答案的组合,在您的根app.ts中将其添加到提供者中:

@Component({
    templateUrl: 'build/app.html',
    providers: [
        anotherProvider,
        { provide: Window, useValue: window }
    ]
})
然后在您的服务中,etc将其注入构造函数

constructor(
      @Inject(Window) private _window: Window,
)

在Angular RC4中,以下是上述一些答案的组合,在您的根app.ts中将其添加到提供者中:

@Component({
    templateUrl: 'build/app.html',
    providers: [
        anotherProvider,
        { provide: Window, useValue: window }
    ]
})
然后在您的服务中,etc将其注入构造函数

constructor(
      @Inject(Window) private _window: Window,
)

为了让它在Angular 2.1.1上运行,我必须使用字符串
@注入
窗口

  constructor( @Inject('Window') private window: Window) { }
然后像这样嘲笑它

beforeEach(() => {
  let windowMock: Window = <any>{ };
  TestBed.configureTestingModule({
    providers: [
      ApiUriService,
      { provide: 'Window', useFactory: (() => { return windowMock; }) }
    ]
  });
{ provide: 'Window', useValue: window }

为了让它在Angular 2.1.1上运行,我必须使用字符串
@注入
窗口

  constructor( @Inject('Window') private window: Window) { }
然后像这样嘲笑它

beforeEach(() => {
  let windowMock: Window = <any>{ };
  TestBed.configureTestingModule({
    providers: [
      ApiUriService,
      { provide: 'Window', useFactory: (() => { return windowMock; }) }
    ]
  });
{ provide: 'Window', useValue: window }

Angular 4引入了一个令牌,它们还为名为的文档创建了一个令牌。我认为这是官方的解决方案,它在AoT中工作

我使用相同的逻辑创建了一个名为的小型库,以防止重复执行此操作

我在其他项目中使用过它,并在AoT中构建,没有任何问题

下面是我在中如何使用它

这是你的电话号码

在您的模块中


进口:[B]