Angular &引用;异步;管道不渲染流更新

Angular &引用;异步;管道不渲染流更新,angular,rxjs,rxjs5,angular2-changedetection,Angular,Rxjs,Rxjs5,Angular2 Changedetection,尝试使用async管道通过angular 2组件中的流渲染窗口大小调整窗口大小: Size:{{Size$| async | json}} const windowSize$=new BehaviorSubject(getWindowSize()); 可观察的.fromEvent(窗口“调整大小”) .map(GetWindowsSize) 。订阅(WindowsSize$); 函数getWindowsSize(){ 返回{ 高度:window.innerHeight, 宽度:window.in

尝试使用
async
管道通过angular 2组件中的流渲染窗口大小调整窗口大小:

Size:{{Size$| async | json}}

const windowSize$=new BehaviorSubject(getWindowSize());
可观察的.fromEvent(窗口“调整大小”)
.map(GetWindowsSize)
。订阅(WindowsSize$);
函数getWindowsSize(){
返回{
高度:window.innerHeight,
宽度:window.innerWidth
};
}
@组成部分({
选择器:“我的应用程序”,
提供者:[],
模板:`
大小:{Size$| async | json}
`,
指令:[]
})
导出类应用程序{
size$=windowSize$.do(o=>console.log('size:',o));
构造函数(){}
}
但该组件仅呈现初始状态,并忽略流更新。 如果打开控制台,在调整窗口大小时,您将看到来自同一流的更新

我不明白我在这里错过了什么


下面是一个事件处理程序在角度区域之外运行的例子,因此当事件触发时,角度变化检测不会运行。将事件处理程序放入组件中,然后它将与所有其他异步事件一起得到修补,因此角度变化检测将在每个事件后执行(并更新视图):


注释中讨论的另一个选项是在更新视图模型时:

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


请注意,您可能希望尝试在根组件中运行一次
ApplicationRef.tick()
,它将在所有组件上运行更改检测,而不是在每个组件中运行
ChangeDetectorRef.detectChanges()
。(您可能需要将
tick()
包装在
setTimeout()
方法中,以确保所有组件视图模型都已更新……我不确定何时将执行所有
do()
回调方法,即,它们是否都在JavaScript VM的一个回合中运行,或者是否涉及多个回合。)

因为我的目标是能够在不同的模块中抽象窗口大小的流,显然只是将流包装在一个类中就完成了交易:

“这是未来”版本:

从“rxjs”导入{Observable,BehaviorSubject};
导出类窗口大小{
宽度$:可见;
高度$:可观察到;
构造函数(){
让windowSize$=createWindowSize$();
this.width$=(WindowsSize$.Purch('width')作为可观察值);
this.height$=(WindowsSize$.Purch('height')作为可观察值);
}
}
const createWindowsSize$=()=>
可观察的.fromEvent(窗口“调整大小”)
.map(GetWindowsSize)
.startWith(GetWindowsSize())
.publishReplay(1)
.refCount();
常量GetWindowsSize=()=>{
返回{
高度:window.innerHeight,
宽度:window.innerWidth
}
};
“奶奶”版:

从“rxjs”导入{Observable,BehaviorSubject};
导出类窗口大小{
宽度$:可见;
高度$:可观察到;
构造函数(){
让WindowsSize$=新行为子对象(GetWindowsSize());
this.width$=(WindowsSize$.Purch('width')作为可观察值);
this.height$=(WindowsSize$.Purch('height')作为可观察值);
可观察的.fromEvent(窗口“调整大小”)
.map(GetWindowsSize)
。订阅(WindowsSize$);
}
}
函数getWindowsSize(){
返回{
高度:window.innerHeight,
宽度:window.innerWidth
};
}

虽然我不想在这个模块中使用类/服务,只需要清晰的/独立于平台的构造,但这是唯一一种清晰的方式,可以在angular上工作,而无需关心触发区域更新。

Heh,这肯定解决了问题。有点过时了。。但在我的实现中,我希望将大小流抽象到另一个文件(没有组件,没有ngOnInit)中,并根据需要为所有组件显示映射的height$和width$流。如何让区域知道这些流更新?@Birowsky,一种方法是在您进行视图模型更改后手动运行更改检测:,这里有一个plunker显示:很好的解决方案。我很好奇,
@Injectable()。所以我的问题仍然存在。我还在想/问这个用例是否有什么不同。我的直觉是这里不需要
@Injectable
。(但是,我知道始终包含
@可注入的
装饰器是一种最佳实践。)@MarkRajcok抱歉,我认为这是推断:现在我将此作为服务,其余组件确实依赖于此,我确实是通过依赖注入来实现的,正是依赖注入使这些流在角度执行上下文(区域)中运行。所以现在它在da区@MarkRajcok你应该把钱放在上面。它不需要
@Injectable()
ngOnInit() {
    Observable.fromEvent(window, 'resize')
     .map(getWindowSize)
     .subscribe(windowSize$);
}
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) {}
}
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
  }
};
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
    };
}