Stop the horrible clash between single and double clicks in Angular
Have you ever wanted your app to behave differently on single-clicking and double-clicking? Sounds like an easy one to implement right? Wrong!
The issue is that the browser also interprets a double click as two single clicks and causes BOTH your event handlers to fire causing bloodshed and destruction 😭
We can neatly solve this problem by using the power of RxJs Subjects and preventing event bubbling using an ergonomic directive:
Explanation:
- We have moved our click handling strategy into a directive so that we can reuse it easily on any DOM node in our Angular template
- We have declared a
Subject
to hold the stream of our click events - By binding to both events using
HostListener
the directive, we prevent the bubbling and default behaviour of these events and pump the event into our clicks subject - The problem is that both
click
anddblclick
events bubble upwards so on double-clicking, the single click handler will fire twice and then the double click handler will fire once. We need to stop this bubbling! - The browser specs guarantee the order of the
dblclick
event always occurring AFTER theclick
event. So, by using thedebounceTime
operator we can control the “speed” of the double-clicking. This will help us differentiate betweenclick
anddblclick
events. After the debounce window, if the value emitted by the clicks subject is not a double click, then it is definitely a single click. - The `selector` of this directive also matches the output event names. This makes our usage API ergonomic and succinct as seen below:
// In some angular template bind to events `click.single` and `click.double`
<div (click.single)="onSingleClick($event)" (click.double)="onDoubleClick(event)">
I got 99 problems but the click ain't one
</div>
And we’re done 🎉🎉🎉
Hope you found this useful
Happy Engineering!