Angular2 – Как вставить окно в услугу с угловым2

Я пишу службу Angular2 в TypeScript, которая будет использовать localstorage. И я хочу вставить ссылку на объект windows браузера в мою службу, так как я не хочу ссылаться на какие-либо глобальные переменные. Как угловое $window 1.x $window . Как мне это сделать?

Это работает для меня в настоящее время (2018-03, угловой 5.2 с AoT, проверен в угловом клипе и пользовательской сборке webpack):

Во-первых, создайте инъекционную службу, которая предоставляет ссылку на окно:

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

а затем, когда вам нужно ввести window :

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

Вы также можете добавить nativeDocument и другие глобальные переменные для этой службы аналогичным образом, если вы используете их в своем приложении.


edit: Обновлено с предложением Truchainz. edit2: Обновлено для углового 2.1.2 edit3: Добавлены примечания AoT edit4: Добавление any вида обходной заметки edit5: Обновленное решение для использования WindowRefService, которое исправляет ошибку, которую я получал при использовании предыдущего решения с другой версией edit6: добавление примера пользовательского ввода текста

С выпуском углового 2.0.0-rc.5 был введен 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) {} } 

Вы также можете использовать OpaqueToken вместо строки «Window»

Редактировать:

AppModule используется для загрузки вашего приложения в main.ts следующим образом:

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

Для получения дополнительной информации о NgModule читайте документацию Angular 2: https://angular.io/docs/ts/latest/guide/ngmodule.html

Вы можете просто ввести его после того, как вы установили поставщика:

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

вот услуга, которую я сделал для вас. https://gist.github.com/gdi2290/f8a524cdfb1f54f1a59c

вы также можете
import {WINDOW, WINDOW_PROVIDERS} from './window-service';
или
import {WindowRef, WINDOW_PROVIDERS} from './window-service';

 @Component({ providers: [WINDOW_PROVIDERS] }) class App { constructor(win: WindowRef, @Inject(WINDOW) win2) { var $window = win.nativeWindow; var $window2 = win2; } } 

Чтобы заставить его работать на Angular 2.1.1, я должен был @Inject окно @Inject используя строку

  constructor( @Inject('Window') private window: Window) { } 

а затем издеваться над этим

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

и в обычном @NgModule я предоставляю его так

 { provide: 'Window', useValue: window } 

Я использовал OpaqueToken для строки «Window»:

 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: [] }), ]; 

И используется для импорта WINDOW_PROVIDERS в bootstrap в 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 { } 

и только что определен в свойствах импорта моего основного app.module.ts

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

Перед объявлением @Component вы тоже можете это сделать,

 declare var window: any; 

Теперь компилятор позволит вам получить доступ к глобальной переменной windows, поскольку вы объявляете ее как предполагаемую глобальную переменную с типом any.

Я бы не предлагал обращаться к окну повсюду в вашем приложении, хотя вам следует создавать службы, которые получают доступ / модифицируют необходимые атрибуты windows (и внедряют эти службы в ваши компоненты) в объем, который вы можете делать с окном, не позволяя им изменять объект всего windows.

На сегодняшний день (апрель 2016 года) код в предыдущем решении не работает, я думаю, что можно сразу вводить окно в App.ts, а затем собирать нужные вам значения в службу глобального доступа в приложении, но если вы предпочитаете создавать и вводить свой собственный сервис, это проще.

https://gist.github.com/WilldelaVega777/9afcbd6cc661f4107c2b74dd6090cebf

 //-------------------------------------------------------------------------------------------------- // Imports Section: //-------------------------------------------------------------------------------------------------- import {Injectable} from 'angular2/core' import {window} from 'angular2/src/facade/browser'; //-------------------------------------------------------------------------------------------------- // Service Class: //-------------------------------------------------------------------------------------------------- @Injectable() export class WindowService { //---------------------------------------------------------------------------------------------- // Constructor Method Section: //---------------------------------------------------------------------------------------------- constructor(){} //---------------------------------------------------------------------------------------------- // Public Properties Section: //---------------------------------------------------------------------------------------------- get nativeWindow() : Window { return window; } } 

В Angular RC4 следующие работы, которые представляют собой комбинацию некоторых из вышеперечисленных ответов, в корневом приложении app.ts добавляют ее поставщикам:

 @Component({ templateUrl: 'build/app.html', providers: [ anotherProvider, { provide: Window, useValue: window } ] }) 

Затем в вашем сервисе и т. Д. Вставьте его в конструктор

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

Угловые 4 вводят InjectToken, а также создают токен для документа под названием DOCUMENT . Я думаю, что это официальное решение, и оно работает в AoT.

Я использую ту же логику, чтобы создать небольшую библиотеку под названием ngx-window-token, чтобы предотвратить повторение этого снова и снова.

Я использовал его в другом проекте и без проблем создавал AoT.

Вот как я использовал его в другой упаковке

Вот плункер

В вашем модуле

imports: [ BrowserModule, WindowTokenModule ] В вашем компоненте

constructor(@Inject(WINDOW) _window) { }

Я знаю, вопрос заключается в том, как вставить объект windows в компонент, но вы делаете это только для того, чтобы добраться до localStorage. Если вы действительно просто хотите localStorage, почему бы не использовать сервис, который предоставляет именно это, например h5webstorage . Затем компонент будет описывать его реальные зависимости, которые делают ваш код более читабельным.

Достаточно сделать

 export class AppWindow extends Window {} 

и делай

 { provide: 'AppWindow', useValue: window } 

сделать AOT счастливым

Вы можете использовать NgZone на угловом 4:

 import { NgZone } from '@angular/core'; constructor(private zone: NgZone) {} print() { this.zone.runOutsideAngular(() => window.print()); } 

Существует возможность прямого доступа к объекту windows через документ

 document.defaultView == window 

Это самый короткий / самый чистый ответ, который я нашел, работая с Angular 4 AOT

Источник: https://github.com/angular/angular/issues/12631#issuecomment-274260009

 @Injectable() export class WindowWrapper extends Window {} export function getWindow() { return window; } @NgModule({ ... providers: [ {provide: WindowWrapper, useFactory: getWindow} ] ... }) export class AppModule { constructor(w: WindowWrapper) { console.log(w); } } 

@maxisam спасибо за токен ngx-window . Я делал что-то подобное, но переключился на твое. Это мой сервис для прослушивания событий изменения размера windows и уведомления абонентов.

 import { Inject, Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/fromEvent'; import { WINDOW } from 'ngx-window-token'; export interface WindowSize { readonly width: number; readonly height: number; } @Injectable() export class WindowSizeService { constructor( @Inject(WINDOW) private _window: any ) { Observable.fromEvent(_window, 'resize') .auditTime(100) .map(event => {width: event['currentTarget'].innerWidth, height: event['currentTarget'].innerHeight}) .subscribe((windowSize) => { this.windowSizeChanged$.next(windowSize); }); } readonly windowSizeChanged$ = new BehaviorSubject({width: this._window.innerWidth, height: this._window.innerHeight}); } 

Держите это просто, люди!

 export class HeroesComponent implements OnInit { heroes: Hero[]; window = window; } 
{{window.Object.entries({ foo: 1 }) | json}}

Получение объекта window через DI (Injection Dependency) не является хорошей идеей, когда глобальные переменные доступны во всем приложении.

Но если вы не хотите использовать оконный объект, вы также можете использовать ключевое слово self которое также указывает на объект windows.

Interesting Posts

Ошибка «строка не удалось разрешить» в Eclipse для C ++ (Eclipse не может разрешить стандартную библиотеку)

Почему скорость загрузки ниже, чем скорость загрузки в обычных интернет-соединениях?

Получить тип сети

У Google Chrome нет автоматической синхронизации закладки, когда пользователь нажимает CTRL-D?

IE предлагает открыть или сохранить результат json с сервера

System32 и SysWOW64 для Windows 7

javac error: имена classов принимаются только в том случае, если обработка annotations явно запрашивается

Как найти список возможных слов из матрицы букв

Информация о сериализации типов кеша Json.NET?

coca pod Диаграмма не появляется (Swift4)

Как получить обратный вызов для MongoDB collection.find ()

Почему индексы массива равны нулю на большинстве языков программирования?

Почему мой LD_LIBRARY_PATH получает неустановленный запуск терминала?

Как преобразовать String в & ‘static str

Не удается прочитать свойство «push» неопределенного (…) в угловом2

Давайте будем гением компьютера.