Prerequisites
Ionic Framework Version
- [ ] v4.x
- [X] v5.x
- [X] v6.x
- [ ] Nightly
Current Behavior
Changes in @HostListener()
on document:click
, document:pointerdown
and document:click
(probably, more events are affected) are not processed by Angular change detection.
Expected Behavior
Changes in @HostListener()
should be processed by Angular change detection.
Steps to Reproduce
- Add a method like this to the page or component:
@HostListener("document:click")
onDocumentClick() {
this.documentClickCount++;
}
- Output
documentClickCount
in your HTML.
- Tap on the screen.
- You'll see that it updates in a browser on both PC and Android, but doesn't in an Android app (apk).
The same thing happens with document:pointerdown
and document:pointerup
events. Maybe more events are affected.
I suspect that change detection is not triggered in such @HostListener
-s for some reason. This is backed by the fact that provided workarounds work.
Code Reproduction URL
https://github.com/matafokka/ionic-hostlistener-bug-demo
Ionic Info
[WARN] Error loading @capacitor/ios package.json: Error: Cannot find module '@capacitor/ios/package'
Require stack:
- C:\Users\matafokka\AppData\Roaming\npm\node_modules\@ionic\cli\lib\project\index.js
- C:\Users\matafokka\AppData\Roaming\npm\node_modules\@ionic\cli\lib\index.js
- C:\Users\matafokka\AppData\Roaming\npm\node_modules\@ionic\cli\index.js
- C:\Users\matafokka\AppData\Roaming\npm\node_modules\@ionic\cli\bin\ionic
Ionic:
Ionic CLI : 6.20.1 (C:\Users\matafokka\AppData\Roaming\npm\node_modules\@ionic\cli)
Ionic Framework : @ionic/angular 6.4.1
@angular-devkit/build-angular : 15.0.4
@angular-devkit/schematics : 15.0.4
@angular/cli : 15.0.4
@ionic/angular-toolkit : 6.1.0
Capacitor:
Capacitor CLI : 4.6.1
@capacitor/android : 4.6.1
@capacitor/core : 4.6.1
@capacitor/ios : not installed
Utility:
cordova-res : 0.15.4
native-run : 1.7.1
System:
NodeJS : v16.14.0 (C:\Program Files\nodejs\node.exe)
npm : 8.3.1
OS : Windows 10
Additional Information
Intro
I've created a demo repo for this problem where I've provided additional info on the problem. I will cite the important parts from it below.
Comments
ionic info
reported wrong Windows version, mine is Windows 11 Pro for Workstations.
- I've tested the demo in Android Studio emulator (Resizable, Android 13) and on Vivo Y31 (Android 12).
- I don't know if this issue persists on IOS.
NgZone.run() workaround
I prefer this one since you just need to wrap your code in it.
constructor(private zone: NgZone) {}
@HostListener("document:click")
onDocumentClick() {
this.zone.run(() => this.documentClickCount++);
}
ChangeDetectorRef workaround
With this you'll need to call ChangeDetectorRef.detectChanges()
every time you return
from your handler.
constructor(private changeDetectorRef: ChangeDetectorRef) {}
@HostListener("document:click")
onDocumentClick() {
this.documentClickCount++;
this.changeDetectorRef.detectChanges();
}
Misc observations
These observations most likely are irrelevant, but I feel like I should post it anyway. Here I'll cite the code from the demo source:
// Document event listeners
@HostListener("document:click")
onDocumentClick() {
this.documentClickCount++;
console.log("[BUG] Document click count:", this.documentClickCount);
}
@HostListener("document:pointerdown")
onDocumentPointerDown() {
this.documentPointerDownCount++;
console.log("[BUG] Document pointer down count:", this.documentPointerDownCount);
}
@HostListener("document:pointerup")
onDocumentPointerUp() {
this.documentPointerUpCount++;
console.log("[BUG] Document pointer up count:", this.documentPointerUpCount);
}
// Window event listeners
// These seem to work just fine.
// I've provided description on document event listener behavior changes when uncommenting window event listeners.
// I'm sure that this is irrelevant to the problem, but I felt like I still should do it.
// Uncommentig only this one makes document listeners update on click.
// document:pointerup and document:pointerdown events fired when holding finger or swiping still don't work.
/*
@HostListener("window:click")
onWindowClick() {
this.windowClickCount++;
console.log("[BUG] Window click count:", this.windowClickCount);
}
*/
// Uncommenting only this one makes:
// 1. document:pointerdown work.
// 2. document:click update from 0 and after holding or swiping only after second click. Displayed value is: documentClickCount - 1.
// 3. document:pointerup update from 0 only after second click. Displayed value is: documentPointerUpCount - 1.
/*
@HostListener("window:pointerdown")
onWindowPointerDown() {
this.windowPointerDownCount++;
console.log("[BUG] Window pointer down count:", this.windowPointerDownCount);
}
*/
// Uncommenting only this one makes:
// 1. document:pointerdown and document:pointerup update on first click.
// 2. document:click update after second click.
// 3. Everything update after holding or swiping and after click. Displayed values are competely off.
// Well, the behavior is weird, and I might have missed something in the list above.
/*
@HostListener("window:pointerup")
onWindowPointerUp() {
this.windowPointerUpCount++;
console.log("[BUG] Window pointer up count:", this.windowPointerUpCount);
}
*/
needs: reply