strategy force detectchanges changedetection change angular rxjs rxjs5 angular2-changedetection

angular - force - La tubería "asincrónica" no muestra las actualizaciones de la transmisión



detectchanges angular 4 (2)

Intentando hacer que el tamaño de la ventana en el tamaño de la ventana cambie a través de una secuencia en un componente angular 2 utilizando una tubería 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() { } }

Pero el componente solo representa el estado inicial e ignora las actualizaciones de la transmisión. Si abre la consola, al cambiar el tamaño de la ventana, verá las actualizaciones de esa misma transmisión.

No puedo entender lo que me falta aquí.

Aquí hay un plunker


Como mi objetivo era poder abstraer las secuencias de tamaño de ventana en un módulo diferente, al parecer, simplemente envolviendo las transmisiones en una clase selló el trato:

"Esta es la versión futura":

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

Versión "Granny":

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

Aunque no quería clase / servicio en este módulo, solo construcciones claras / independientes de plataforma, esta era la única manera limpia que funcionaba para angular sin tener que preocuparse por activar actualizaciones de zona.


El controlador de eventos se está ejecutando fuera de la zona angular, por lo que la detección de cambios angulares no se ejecuta cuando se activa un evento. Coloque el controlador de eventos dentro de su componente y luego obtendrá parche de mono junto con todos los otros eventos asíncronos, por lo tanto, la detección de cambio angular se ejecutará después de cada evento (y actualizará la vista):

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

Plunker

Otra opción, comentada en los comentarios, es ejecutar manualmente la detección de cambios cuando se actualiza un modelo de vista:

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

Tenga en cuenta que en su lugar podría intentar ejecutar ApplicationRef.tick() una vez, por ejemplo, en su componente raíz, que ejecutará la detección de cambios en todos los componentes, en lugar de ejecutar ChangeDetectorRef.detectChanges() en cada componente. (Y es posible que tenga que ajustar tick() dentro de un método setTimeout() para asegurarse de que se actualizaron todos los modelos de vista de componentes ... No estoy seguro de cuándo se ejecutarán todos los métodos de devolución de llamada do() - es decir, si todos se ejecutan en un turno de la máquina virtual JavaScript, o si se trata de varios turnos).