After upgrading from Ionic 8.7.3 to 8.7.4 (and also tested in 8.7.7), I encountered a critical issue with click event handling in my app. The issue seems to be related to how HostListener bound click events are processed in Ionic components.
In my app, I use HostListener to listen for click events on elements like ion-button and ion-item to display a modal. This worked perfectly in 8.7.3, but starting from 8.7.4, the app exhibits the following behavior:
- When I click on a field to display a modal, the modal opens as expected.
- However, every subsequent click is incorrectly linked to the previous field, causing the modal to repeatedly dismiss and reopen. This behavior makes the app unusable, as the click events are not being properly reset or handled.
Ionic CLI: 7.2.1
Ionic Framework: @ionic/angular 8.7.7
@angular-devkit/build-angular : 20.3.5
@angular-devkit/schematics : 20.3.6
@angular/cli: 20.3.5
@ionic/angular-toolkit: 12.3.0
I have recorded two videos demonstrating the behavior:
Working in 8.7.3: Video Link
Issue in 8.7.7: Video Link
Code Example
Here is the directive we are using:
import {
Directive, EventEmitter,
HostListener,
Input,
OnDestroy,
OnInit,
Output
} from ‘@angular/core’;
import { Subject, Subscription } from ‘rxjs’;
import { debounceTime } from ‘rxjs/operators’;
@Directive({
selector: ‘[appDebounceClick]’,
standalone: true
})
export class DebounceClickDirective implements OnInit, OnDestroy {
constructor() { }
@Input() debounceTime = 200;
@Output() debounceClick = new EventEmitter();
private clicks = new Subject();
private subscription: Subscription;
private lastEmitMills = new Date().valueOf();
ngOnInit(): void {
this.subscription = this.clicks.pipe(
debounceTime(this.debounceTime)
).subscribe(e => {
this.lastEmitMills = new Date().valueOf();
this.debounceClick.emit(e);
});
}
ngOnDestroy(): void {
this.subscription?.unsubscribe();
}
@HostListener(‘click’, [‘$event’])
clickEvent(event: Event): void {
event.stopPropagation();
const currentMillis = new Date().valueOf();
if ((currentMillis - this.lastEmitMills) * 0.5 > this.debounceTime) {
this.clicks.next(event);
}
}
}