I was looking for both single and double-click event handling with AngularJS, since AngularJS always fires only the ng-click event even if there is ng-dblclick directive set for our element.
Here is some working code for those who seek solution:
JS:
function MyController($scope) {
var waitingForSecondClick = false;
$scope.singleClickAction = function() {
executingDoubleClick = false;
if (waitingForSecondClick) {
waitingForSecondClick = false;
executingDoubleClick = true;
return $scope.doubleClickAction();
}
waitingForSecondClick = true;
setTimeout(function() {
waitingForSecondClick = false;
return singleClickOnlyAction();
}, 250); // delay
/*
* Code executed with single AND double-click goes here.
* ...
*/
var singleClickOnlyAction = function() {
if (executingDoubleClick) return;
/*
* Code executed ONLY with single-click goes here.
* ...
*/
}
}
$scope.doubleClickAction = function() {
/*
* Code executed ONLY with double-click goes here.
* ...
*/
};
}
HTML:
<div ng-controller="MyController">
<a href="#" ng-click="singleClickAction()">CLICK</a>
</div>
So my question is (since I'm an AngularJS newbie): could somebody more experianced write some nice directive for handling those both events?
In my opinion the perfect way would be to change the behaviour of ng-click, ng-dblclick and add some "ng-sglclick" directive for handling single-click-only code. Don't know if it is even possible, but I'd find it very useful for everyone.
Feel free to share your opinions!
Greg's answer is definitely closest to the cleanest answer. I'm going to build on his answer to come up with a version where no new code needs to be written, and no new injections need to be used in your controller.
The first thing to question is why timeouts are used to hack around these kinds of problems. Essentially, they're used to make a function skip the rest of the current event loop so that the execution is clean. In angular, however, you are actually interested in how the digest loop works. It's almost the same as your classic event handler, except for some minor differences which make it great for UX. Some tools that you have on hand to mess around with the order of function execution include
scope.$eval
,scope.$evalAsync
,scope.$apply
, andscope.$applyAsync
.I believe the
$apply
s will kick off another digest loop, which leaves the$eval
s.$eval
will run whatever code you include immediately with the context of the current$scope
and$evalAsync
will queue your function to be run at the end of the digest loop. Essentially,$evalAsync
is a cleaner version of$timeout
with one big difference — the first has context and exists on the scope!This means that you can, actually, handle
ng-click
andng-dblclick
on the same element. Note, however, that this will still trigger the single-click function before the double-click function. This should be sufficient:Here's a jsfiddle with the intended functionality using Angular 1.6.4.
You could just write your own. I took a look at how angular handled click and modified it with code I found here: Jquery bind double click and single click separately
Here's an example
Plunker
Joining the pieces of the answers here:
directive
, as @Rob (the one accepted as best answer in this thread)ngClick
build-in directive by using @EricChen answerHere the Plunker with the essence of the idea (same as snippet in this answer; see below).
Aside note: ideally, if there is no
ng-dblclick
defined for the element, it shouldn't prevent the single click (here a Plunker fork implementing this idea)Came across this and thought I'd throw out an alternative. It's not too different from the original poster aside from two key points.
1) There's no nested function declarations.
2) I use $timeout. I often use $timeout even without a delay...especially if I'm kicking off promises to do other work. The $timeout will fire when the digest cycle comes through which makes sure that any data changes to scope get applied.
Given
In your controller the singleClick function will look like:
And the doubleClick function will look normal:
Hope this helps someone...
it works too if calling
singleClick
on thedoubleClick
doesn't make any mistakeI ran across while trying to find a way to handle double click and click at the same time. I used the concepts here to cancel the original click. If a second click occurs before the delay, the double click action performed. If there is not a second click, once the delay is over, the default ngClick action runs and the original event is triggered on the element (and allowed to bubble like it would have initially).
Example
Code