16

asyncパイプを利用するAngular 2コンポーネントのストリームを介して、ウィンドウのサイズ変更時にウィンドウサイズをレンダリングしようとしています:

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

ただし、コンポーネントは初期状態のみをレンダリングし、ストリームの更新を無視します。コンソールを開くと、ウィンドウのサイズ変更時に、同じストリームからの更新が表示されます。

ここで何が欠けているのか理解できません。

ここにプランカーがあります

4

3 に答える 3

14

イベント ハンドラーは Angular ゾーンの外で実行されているため、イベントが発生しても Angular の変更検出は実行されません。コンポーネント内にイベント ハンドラーを配置すると、他のすべての非同期イベントと共にモンキー パッチが適用されます。したがって、各イベントの後に Angular 変更検出が実行されます (そしてビューが更新されます)。

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

Plunker


コメントで説明されている別のオプションは、ビュー モデルが更新されたときに変更検出を手動で実行することです。

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

ApplicationRef.tick()各コンポーネントで実行するのではなく、すべてのコンポーネントで変更検出を実行する、たとえばルート コンポーネントで 1 回実行することをお勧めしChangeDetectorRef.detectChanges()ます。tick()(そして、すべてのコンポーネント ビュー モデルが更新されたことを確認するために、メソッド内でラップする必要があるかもしれませんsetTimeout()...すべてのdo()コールバック メソッドがいつ実行されるか、つまり、すべてが一度に実行されるかどうかはわかりません。 JavaScript VM の場合、または複数のターンが関係している場合)。

于 2016-02-19T19:26:24.887 に答える