我有一个尚未实例化的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;
}
}
答案 0 :(得分:1)
似乎正在发生的事情是,<hello/>
组件的渲染是在与单击按钮相同的Zone.js任务中进行的。因此,事件的顺序(在同一任务中)将是:
<button/>
showOtherComponent
中的<my-app/>
更改为true
<my-app/>
点击监听器,并开始检测变化<hello/>
组件应被渲染,以便对其进行渲染/实例化 这都是在文档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。