Yanıtlar:
Bu şu anda benim için çalışıyor (2018-03, AoT ile açısal 5.2, açısal-cli ve özel bir web paketi yapısında test edildi):
İlk olarak, pencereye bir referans sağlayan enjekte edilebilir bir servis oluşturun:
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();
}
}
Şimdi, bu hizmeti kök AppModule'ünüze kaydedin, böylece her yere enjekte edilebilir:
import { WindowRefService } from './window-ref.service';
@NgModule({
providers: [
WindowRefService
],
...
})
export class AppModule {}
ve daha sonra enjekte etmeniz gereken yere 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;
}
...
Bunları uygulamanızda nativeDocument
kullanırsanız, bu hizmete ve diğer küreselleri de benzer şekilde eklemek isteyebilirsiniz .
düzenleme: Truchainz önerisiyle güncellendi. edit2: Açısal 2.1.2 için güncellendi edit3: Eklendi AoT notları edit4: any
Tip geçici çözüm notu ekleme edit5: Önceki çözümü farklı bir yapı düzenlemesiyle kullanırken aldığım bir hatayı düzelten bir WindowRefService kullanmak için güncellendi çözüm6: örnek özel Pencere yazma ekleme
@Inject
ben başlamıştı No provider for Window
hataları. Kılavuza ihtiyaç duymamak çok güzel @Inject
!
@Inject(Window)
işe yaraması için kullanmak zorunda kaldım
window
, ancak aradaki hizmet, window
birim testlerinde yerel öğelerin çıkmasına izin veriyor ve SSR için de belirttiğiniz gibi, sunucu için bir sahte / noop penceresi ortaya çıkaran alternatif bir hizmet sağlanabilir. AOT'den bahsetmemin nedeni, Angular güncellendiğinde AOT'de pencere sarma için ilk çözümlerin birkaçının kırılmasıdır.
Açısal 2.0.0-rc.5 NgModule'un piyasaya sürülmesiyle birlikte tanıtıldı. Önceki çözüm benim için çalışmayı bıraktı. Bunu düzeltmek için yaptığım şey buydu:
app.module.ts:
@NgModule({
providers: [
{ provide: 'Window', useValue: window }
],
declarations: [...],
imports: [...]
})
export class AppModule {}
Bazı bileşenlerde:
import { Component, Inject } from '@angular/core';
@Component({...})
export class MyComponent {
constructor (@Inject('Window') window: Window) {}
}
'Pencere' dizesi yerine bir OpaqueToken da kullanabilirsiniz.
Düzenle:
AppModule, uygulamanızı main.ts'de şu şekilde önyüklemek için kullanılır:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule)
NgModule hakkında daha fazla bilgi için Angular 2 belgelerini okuyun: https://angular.io/docs/ts/latest/guide/ngmodule.html
Sağlayıcıyı ayarladıktan sonra enjekte edebilirsiniz:
import {provide} from 'angular2/core';
bootstrap(..., [provide(Window, {useValue: window})]);
constructor(private window: Window) {
// this.window
}
window.var
sayfanın içeriğini değiştirdiğimde değişmiyor
Enjekte edilen belgeden pencere alabilirsiniz.
import { Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';
export class MyClass {
constructor(@Inject(DOCUMENT) private document: Document) {
this.window = this.document.defaultView;
}
check() {
console.log(this.document);
console.log(this.window);
}
}
Angular 2.1.1'de çalışmasını sağlamak @Inject
için bir dizge kullanarak pencereye gitmem gerekiyordu
constructor( @Inject('Window') private window: Window) { }
ve sonra böyle alay et
beforeEach(() => {
let windowMock: Window = <any>{ };
TestBed.configureTestingModule({
providers: [
ApiUriService,
{ provide: 'Window', useFactory: (() => { return windowMock; }) }
]
});
ve sıradan olarak @NgModule
bunu böyle sağlıyorum
{ provide: 'Window', useValue: window }
Angular RC4'te, yukarıdaki cevaplardan bazılarının bir kombinasyonu olan aşağıdaki çalışır, kök uygulamanızda sağlayıcıları ekleyin:
@Component({
templateUrl: 'build/app.html',
providers: [
anotherProvider,
{ provide: Window, useValue: window }
]
})
Sonra hizmetinizde vb kurucuya enjekte edin
constructor(
@Inject(Window) private _window: Window,
)
@Component bildiriminden önce bunu da yapabilirsiniz,
declare var window: any;
Herhangi bir tipte varsayılan bir global değişken olarak tanımladığınızdan, derleyici aslında global pencere değişkenine erişmenize izin verecektir.
Yine de uygulamanızın her yerinden pencereye erişmenizi önermem. Pencereyle yapabileceklerinizi, pencereyi değiştirmelerine izin vermeden kapsamak için gerekli pencere özniteliklerine erişen / bunları değiştiren (ve bileşenlerinize bu hizmetleri enjekte eden) hizmetler oluşturmalısınız. tüm pencere nesnesi.
OpaqueToken'ı 'Pencere' dizesi için kullandım :
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: [] }),
];
Ve sadece WINDOW_PROVIDERS
Angular 2.0.0-rc-4'te bootstrap'e aktarmak için kullanılır .
Ancak Angular 2.0.0-rc.5 sürümüyle birlikte ayrı bir modül oluşturmam gerekiyor:
import { NgModule } from '@angular/core';
import { WINDOW_PROVIDERS } from './window';
@NgModule({
providers: [WINDOW_PROVIDERS]
})
export class WindowModule { }
ve sadece ana sayfamın ithal malında tanımlanmış 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 {}
Angular 4, InjectToken'ı sunar ve ayrıca DOCUMENT adlı belge için bir belirteç oluşturur . Bence bu resmi çözüm ve AoT'de çalışıyor.
Bunu defalarca yapmamak için ngx-window-token adlı küçük bir kitaplık oluşturmak için aynı mantığı kullanıyorum .
Bunu başka bir projede kullandım ve AoT'de sorunsuz bir şekilde inşa ettim.
İşte diğer pakette nasıl kullandım
İşte dalgıç
Senin modülünde
imports: [ BrowserModule, WindowTokenModule ]
Bileşeninizde
constructor(@Inject(WINDOW) _window) { }
Bugün (Nisan 2016) itibariyle, önceki çözümdeki kod çalışmıyor, pencereyi doğrudan Uygulamalara enjekte etmenin ve ardından ihtiyacınız olan değerleri Uygulamada küresel erişim için bir hizmette toplamanın mümkün olduğunu düşünüyorum, ancak Kendi hizmetinizi oluşturmayı ve enjekte etmeyi tercih ediyorsanız, bu daha basit bir çözümdür.
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;
}
}
İşte defaultView
, DOCUMENT
yerleşik belirteçten almaktan ve boş olup olmadığını kontrol etmekten yorulduktan sonra yakın zamanda bulduğum başka bir çözüm :
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;
}
});
@Inject(WINDOW) private _window: any
ve Angular tarafından sağlanan DOCUMENT enjeksiyon jetonu gibi kullanın.
Yapman yeterli
export class AppWindow extends Window {}
ve yap
{ provide: 'AppWindow', useValue: window }
AOT'yi mutlu etmek için
Belge üzerinden pencerenin nesnesine doğrudan erişim imkanı var
document.defaultView == window
Sorunun pencere nesnesinin bir bileşene nasıl enjekte edileceğini biliyorum, ancak bunu sadece localStorage'a ulaşmak için yapıyorsunuz, öyle görünüyor. Gerçekten sadece localStorage istiyorsanız, neden h5webstorage gibi tam da bunu ortaya çıkaran bir hizmet kullanmıyorsunuz ? Daha sonra bileşeniniz, kodunuzu daha okunaklı hale getiren gerçek bağımlılıklarını tanımlayacaktır.
Bu, Angular 4 AOT ile çalışırken bulduğum en kısa / en temiz cevap
Kaynak: 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);
}
}
NgZone'u Angular 4'te kullanabilirsiniz:
import { NgZone } from '@angular/core';
constructor(private zone: NgZone) {}
print() {
this.zone.runOutsideAngular(() => window.print());
}
Ayrıca DOCUMENT
isteğe bağlı olarak işaretlemek de iyi bir fikirdir . Angular belgelerine göre:
Uygulama ve Rendering Contexts aynı olmadığında (örneğin, uygulamayı bir Web Worker'da çalıştırırken), Belge Uygulama Bağlamında mevcut olmayabilir.
DOCUMENT
Tarayıcının SVG desteğine sahip olup olmadığını görmek için burada bir örnek verilmiştir :
import { Optional, Component, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common'
...
constructor(@Optional() @Inject(DOCUMENT) document: Document) {
this.supportsSvg = !!(
document &&
document.createElementNS &&
document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect
);
@maxisam ngx-window-token için teşekkürler . Ben de benzer bir şey yapıyordum ama seninkine geçtim. Bu, pencere yeniden boyutlandırma olaylarını dinlemek ve aboneleri bilgilendirmek için benim hizmetimdir.
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 => <WindowSize>{width: event['currentTarget'].innerWidth, height: event['currentTarget'].innerHeight})
.subscribe((windowSize) => {
this.windowSizeChanged$.next(windowSize);
});
}
readonly windowSizeChanged$ = new BehaviorSubject<WindowSize>(<WindowSize>{width: this._window.innerWidth, height: this._window.innerHeight});
}
Kısa ve tatlıdır ve bir cazibe gibi çalışır.
DI (Bağımlılık Enjeksiyonu) aracılığıyla pencere nesnesi almak, uygulama boyunca global değişkenlere erişilebilir olduğunda iyi bir fikir değildir.
Ancak pencere nesnesini kullanmak istemiyorsanız, pencere nesnesine self
de işaret eden anahtar sözcüğü de kullanabilirsiniz .
Basit tutun millet!
export class HeroesComponent implements OnInit {
heroes: Hero[];
window = window;
}
<div>{{window.Object.entries({ foo: 1 }) | json}}</div>
Aslında buradaki pencere nesnesine erişmek çok basit ve temel bileşenim ve çalıştığını test ettim
import { Component, OnInit,Inject } from '@angular/core';
import {DOCUMENT} from '@angular/platform-browser';
@Component({
selector: 'app-verticalbanners',
templateUrl: './verticalbanners.component.html',
styleUrls: ['./verticalbanners.component.css']
})
export class VerticalbannersComponent implements OnInit {
constructor(){ }
ngOnInit() {
console.log(window.innerHeight );
}
}
ORIGINAL EXCEPTION: No provider for Window!
. Ancak, onu kaldırmak benim için sorunu çözdü. Sadece ilk 2 global hattı kullanmak benim için yeterliydi.