"asynchronous" channel does not transmit stream updates

Attempt to display window size when resizing window through stream in angular 2 component using async :

<h2>Size: {{size$ | async | json}}</h2>

 const windowSize$ = new BehaviorSubject(getWindowSize()); Observable.fromEvent(window, 'resize') .map(getWindowSize) .subscribe(windowSize$); function getWindowSize() { return { height: window.innerHeight, width: window.innerWidth }; } @Component({ selector: 'my-app', providers: [], template: ` <div> <h2>Size: {{size$ | async | json}}</h2> </div> `, directives: [] }) export class App { size$ = windowSize$.do(o => console.log('size:', o)); constructor() { } } 

But the component only displays the initial state and ignores stream updates. If you open the console, when you resize the window, you will see updates from the same stream.

I canโ€™t understand what I donโ€™t see here.

Here plunker

+8
angular rxjs angular2-changedetection rxjs5
Feb 19 '16 at 19:05
source share
2 answers

The event handler runs outside the Angular zone, so when an Angular event is detected, change detection does not start. Put an event handler in your component, and then it will get the monkey patch along with all other asynchronous events, so Angular will detect changes after each event (and update the view):

 ngOnInit() { Observable.fromEvent(window, 'resize') .map(getWindowSize) .subscribe(windowSize$); } 

Plunker




Another option discussed in the comments is to manually trigger change detection when updating the view model:

 import {Component, ChangeDetectorRef} from 'angular2/core' ... export class App { size$ = windowSize$.do(o => { console.log('size:', o); // since the resize event was not registered while inside the Angular zone, // we need to manually run change detection so that the view will update this._cdr.detectChanges(); }); constructor(private _cdr: ChangeDetectorRef) {} } 

Plunker

Note that instead, you can try running ApplicationRef.tick() once, say in the root component, which will trigger change detection on all components - instead of running ChangeDetectorRef.detectChanges() in each component. (And you might need to wrap tick() inside the setTimeout() method to make sure all component view models have been updated ... I'm not sure that all do() callback methods will execute - i.e. if all of them run in one revolution of the JavaScript virtual machine, or take several turns.)

+9
Feb 19 '16 at 19:26
source share

Since my goal was to be able to abstract the window-size threads in another module, apparently just wrapping the threads in the class, sealed the deal:

This is the future version:

 import {Observable, BehaviorSubject} from 'rxjs'; export class WindowSize { width$: Observable<number>; height$: Observable<number>; constructor() { let windowSize$ = createWindowSize$(); this.width$ = (windowSize$.pluck('width') as Observable<number>).distinctUntilChanged(); this.height$ = (windowSize$.pluck('height') as Observable<number>).distinctUntilChanged(); } } const createWindowSize$ = () => Observable.fromEvent(window, 'resize') .map(getWindowSize) .startWith(getWindowSize()) .publishReplay(1) .refCount(); const getWindowSize = () => { return { height: window.innerHeight, width: window.innerWidth } }; 

"Grandma" version:

 import {Observable, BehaviorSubject} from 'rxjs'; export class WindowSize { width$: Observable<number>; height$: Observable<number>; constructor() { let windowSize$ = new BehaviorSubject(getWindowSize()); this.width$ = (windowSize$.pluck('width') as Observable<number>).distinctUntilChanged(); this.height$ = (windowSize$.pluck('height') as Observable<number>).distinctUntilChanged(); Observable.fromEvent(window, 'resize') .map(getWindowSize) .subscribe(windowSize$); } } function getWindowSize() { return { height: window.innerHeight, width: window.innerWidth }; } 

Although I did not need a class / service in this module, just clear / platform-independent designs, it was the only clean way that worked for angular without worrying about starting zone updates.

+12
Feb 20 '16 at 13:50
source share



All Articles