There is a specific component that wraps around a library, and to prevent the chaos of change detection caused by event listeners in this library, the library is kept outside the Angular zone:
@Component({ ... })
export class TestComponent {
@Output()
emitter = new EventEmitter<void>();
constructor(private ngZone: NgZone) {}
ngOnInit() {
this.ngZone.runOutsideAngular(() => {
// ...
});
}
}
This setup is pretty straightforward and commonly used. Now, let's introduce an event to trigger the action:
@Component({ ... })
export class TestComponent {
@Output()
emitter = new EventEmitter<void>();
private lib: Lib;
constructor(private ngZone: NgZone) {}
ngOnInit() {
this.ngZone.runOutsideAngular(() => {
this.lib = new Lib();
});
this.lib.on('click', () => {
this.emitter.emit();
});
}
}
The issue here is that the emitter does not trigger change detection since it operates outside the zone. One way to address this is by reentering the zone:
@Component({ ... })
export class TestComponent {
@Output()
emitter = new EventEmitter<void>();
private lib: Lib;
constructor(private ngZone: NgZone) {}
ngOnInit() {
this.ngZone.runOutsideAngular(() => {
this.lib = new Lib();
});
this.lib.on('click', () => {
this.ngZone.run(() => this.emitter.emit());
});
}
}
Now comes the question. The this.ngZone.run
call enforces change detection even if the event was not subscribed to in the parent component:
<test-component></test-component>
This behavior is undesirable because there are no subscribers for that event => no need for detection.
How can we solve this dilemma?
For those interested in a practical example, the root of this question can be found here.