Angular组件如何捕获实例化之前发生的事件?

时间:2019-02-14 13:03:37

标签: angular

我有一个尚未实例化的Angular组件。它位于* ng内。如果是这样,则当条件设置为true时,它将被实例化并显示在页面上。单击按钮时,将条件设置为true。 在该组件内部,我有一个主机侦听器,它监听click事件。

所以我的问题是,新实例化的组件如何才能捕获实例化之前发生的点击?

这是一个展示问题的堆栈闪电战: https://stackblitz.com/edit/ng-click-lifecycle

@Component({
  selector: 'my-app',
  template: `
  <button (click)="showOtherComponent = true">Show other component</button>
  <hello *ngIf="showOtherComponent"></hello>
`,
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  showOtherComponent = false;
}

@Component({
  selector: 'hello',
  template: `
  <h1>Hello {{name}}!</h1>
  <span *ngIf="caughtClick">I caught the click even though I wasn't instanciated when it happened</span>
  `,
  styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent  {
  @Input() name: string = 'Other component';
  caughtClick = false;

  constructor() {
    console.log('Constructor');
  }

  @HostListener('document:click', ['$event'])
  handleClick(e) {
    console.log('Click handler is called but the click happened before the component was instanciated...');
   this.caughtClick = true;
  }
}

1 个答案:

答案 0 :(得分:1)

似乎正在发生的事情是,<hello/>组件的渲染是在与单击按钮相同的Zone.js任务中进行的。因此,事件的顺序(在同一任务中)将是:

  1. 用户单击“显示其他组件” <button/>
  2. showOtherComponent中的
  3. <my-app/>更改为true
  4. Angular离开了<my-app/>点击监听器,并开始检测变化
  5. 检测到<hello/>组件应被渲染,以便对其进行渲染/实例化
  6. 然后,Angular看到该组件具有用于文档点击的侦听器,因此运行它

这都是在文档click的原始上下文中发生的(如果您查看调试调用堆栈,则所有步骤仍在原始click侦听器中进行)。因此,您的<hello/>组件将被调用。要解决此问题,您只需更改showOtherComponent点击监听器即可在another turn of the event loop上运行:

@Component({
  selector: 'my-app',
  template: `
    <button (click)="toggleComponent()">Show other component</button>
    <hello *ngIf="showOtherComponent"></hello>
  `,
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  showOtherComponent = false;

  toggleComponent(){
    setTimeout(() => {//will run AFTER the click event is finished
       this.showOtherComponent = !this.showOtherComponent;
    });
  }

}

这可确保添加<hello/>组件的单击侦听器在呈现该组件之前已完全完成。 Here's the modified code