首页 > 解决方案 > 当我们删除 HostListener 时,Angular HTML 绑定不起作用

问题描述

为了减少更改检测,我们将 hostlistener 替换为来自 RXJS 的事件和 angular 的 runoutside。

这就是我的角度代码的样子

ngOnInit() {
    this.windowKeyDown();
    // this.subject$ = this.subject.asObservable();
  }

  constructor(private _ngZone: NgZone) {}

  //@HostListener('window:keydown', ['$event'])
  handleKeyboardEvent(event: KeyboardEvent) {
    console.log('handle key fired');
    this.keypressed = event.key;
    this.iskeyPressed = true;
  }

  windowKeyDown() {
    console.log('windowKeyDown');
    fromEvent(window, 'keydown')
      .pipe(this.outsideZone(this._ngZone))
      .subscribe(event => this.handleKeyboardEvent(<KeyboardEvent>event));
  }

  outsideZone<T>(zone: NgZone) {
    return function(source: Observable<T>) {
      return new Observable(observer => {
        let sub: Subscription;
        zone.runOutsideAngular(() => {
          sub = source.subscribe(observer);
        });

        return sub;
      });
    };
  }

和 HTML 绑定是:

<h2>keypressed: {{keypressed}}</h2>
<h2>iskeyPressed: {{iskeyPressed}}</h2>

在这个绑定变量中它自己现在没有更新,你能指导我的代码有什么问题吗?

复制的最小步骤:https ://stackblitz.com/edit/keypress-example-vu3mej?file=app%2Fapp.component.html

标签: javascriptangularrxjsangular2-template

解决方案


我建议将此组件的 ChangeDetectionStrategy 设置为 OnPush。你可以在这里阅读更多关于它的信息。不要在此组件中放置任何您希望自动更改检测的逻辑,因为整个组件都禁用了更改检测。

下面是一个代码示例,展示了如何直接从模板订阅键盘事件(使用异步管道)。

https://stackblitz.com/edit/angular-change-detection-strategy-onpush-g6mjkr?file=src%2Fapp%2Fchild%2Fchild.component.ts

import {
  Component,
  Input,
  ChangeDetectionStrategy,
  OnInit
} from '@angular/core';
import { fromEvent, Observable } from 'rxjs';
import { map, startWith, tap } from 'rxjs/operators';

@Component({
  selector: 'child',
  template: `
    <ng-container *ngIf="keyboard$ | async as keyBoard">
      <h2>keypressed: {{ keyBoard.keypressed }}</h2>
      <h2>iskeyPressed: {{ keyBoard.iskeyPressed }}</h2>
    </ng-container>
  `,
  styleUrls: [],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnInit {
  keyboard$: Observable<{ keypressed: any; iskeyPressed: boolean }>;
  ngOnInit() {
    console.log('bla')
    this.keyboard$ = fromEvent(window, 'keydown').pipe(
      map(event => ({ keypressed: event.key, iskeyPressed: true })),
      startWith({keypressed: null, iskeyPressed: null})
    );
  }
}

推荐阅读