Handling ng-click and ng-dblclick on the same element with AngularJS Handling ng-click and ng-dblclick on the same element with AngularJS angularjs angularjs

Handling ng-click and ng-dblclick on the same element with AngularJS


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

<div sglclick="singleClick()" ng-dblClick="doubleClick()" style="height:200px;width:200px;background-color:black">mainMod.controller('AppCntrl', ['$scope', function ($scope) {    $scope.singleClick = function() {      alert('Single Click');    }    $scope.doubleClick = function() {      alert('Double Click');    }}])mainMod.directive('sglclick', ['$parse', function($parse) {    return {        restrict: 'A',        link: function(scope, element, attr) {          var fn = $parse(attr['sglclick']);          var delay = 300, clicks = 0, timer = null;          element.on('click', function (event) {            clicks++;  //count clicks            if(clicks === 1) {              timer = setTimeout(function() {                scope.$apply(function () {                    fn(scope, { $event: event });                });                 clicks = 0;             //after action performed, reset counter              }, delay);              } else {                clearTimeout(timer);    //prevent single-click action                clicks = 0;             //after action performed, reset counter              }          });        }    };}])

Here's an example

Plunker


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, and scope.$applyAsync.

I believe the $applys will kick off another digest loop, which leaves the $evals. $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 and ng-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:

<div ng-controller="MyController">    <a href="#"       ng-click="$evalAsync(singleClickAction())"       ng-dblclick="doubleClickAction()">       CLICK    </a></div>

Here's a jsfiddle with the intended functionality using Angular 1.6.4.


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

<img src="myImage.jpg" ng-click="singleClick()" ng-dblclick="doubleClick()">

In your controller the singleClick function will look like:

$scope.singleClick = function () {    if ($scope.clicked) {        $scope.cancelClick = true;        return;    }    $scope.clicked = true;    $timeout(function () {        if ($scope.cancelClick) {            $scope.cancelClick = false;            $scope.clicked = false;            return;        }        //do something with your single click here        //clean up        $scope.cancelClick = false;        $scope.clicked = false;    }, 500);};

And the doubleClick function will look normal:

$scope.doubleClick = function () {    $timeout(function () {        //do something with your double click here    });};

Hope this helps someone...