Skip to content

Commit d2fe3a0

Browse files
committed
fix(ngTouch): deprecate ngClick and disable it by default
This commit deprecates the ngClick directive from the ngTouch module. Additionally, it disables it by default. It can be enabled in the new $touchProvider with $touchProvider.ngClickOverrideEnabled() method. The directive was conceived to remove the 300ms delay for click events on mobile browsers, by sending a synthetic click event on touchstart. It also tried to make sure that the original click event that the browser sends after 300ms was "busted", so that no redundant "ghost-clicks" appear. There are various reasons why the directive is being deprecated. - "This is an ugly, terrible hack!" (says so in the source) - It is plagued by various bugs that are hard to fix / test for all platforms (see below) - Simply including ngTouch activates the ngClick override, which means even if you simply want to use ngSwipe, you may break parts of your app - There exist alternatives for removing the 300ms delay, that can be used very well with Angular: [FastClick](https://github.com/ftlabs/fastclick), [Tappy!](https://github.com/filamentgroup/tappy/) (There's also hammer.js for touch events / gestures) - The 300ms delay itself is on the way out - Chrome and Firefox for Android remove the 300ms delay when the usual `<meta name="viewport" content="width=device-width">` is set. In IE, the `touch-action` css property can be set to `none` or `manipulation` to remove the delay. Finally, since iOs 8, Safari doesn't delay "slow" taps anymore. There are some caveats though, which can be found in this excellent article on which this summary is based: http://developer.telerik.com/featured/300-ms-click-delay-ios-8/ Note that this change does not affect the `ngSwipe` directive. Issues with interactive elements (input, a etc.) when parent element has ngClick: Closes angular#4030 Closes angular#5307 Closes angular#6001 Closes angular#6432 Closes angular#7231 Closes angular#11358 Closes angular#12082 Closes angular#12153 Closes angular#12392 Closes angular#12545 Closes angular#12867 Closes angular#13213 Closes angular#13558 Other issues: - incorrect event order - incorrect event propagation - ghost-clicks / failing clickbusting with corner cases - browser specific bugs - et al. Closes angular#3296 Closes angular#3347 Closes angular#3447 Closes angular#3999 Closes angular#4428 Closes angular#6251 Closes angular#6330 Closes angular#7134 Closes angular#7935 Closes angular#9724 Closes angular#9744 Closes angular#9872 Closes angular#10211 Closes angular#10366 Closes angular#10918 Closes angular#11197 Closes angular#11261 Closes angular#11342 Closes angular#11577 Closes angular#12150 Closes angular#12317 Closes angular#12455 Closes angular#12734 Closes angular#13122 Closes angular#13272 Closes angular#13447 BREAKING CHANGE: The `ngClick` override directive from the `ngTouch` module is **deprecated and disabled by default**. This means that on touch-based devices, users might now experience a 300ms delay before a click event is fired. If you rely on this directive, you can still enable it with the `$touchProvider.ngClickOverrideEnabled()`method: ```js angular.module('myApp').config(function($touchProvider) { $touchProvider.ngClickOverrideEnabled(true); }); ``` For migration, we recommend using [FastClick](https://github.com/ftlabs/fastclick). Also note that modern browsers remove the 300ms delay under some circumstances: - Chrome and Firefox for Android remove the 300ms delay when the well-known `<meta name="viewport" content="width=device-width">` is set - Internet Explorer removes the delay when `touch-action` css property is set to `none` or `manipulation` - Since iOs 8, Safari removes the delay on so-called "slow taps" See this [article by Telerik](http://developer.telerik.com/featured/300-ms-click-delay-ios-8/) for more info on the topic. Note that this change does not affect the `ngSwipe` directive.
1 parent adcfa74 commit d2fe3a0

File tree

3 files changed

+662
-465
lines changed

3 files changed

+662
-465
lines changed

src/ngTouch/directive/ngClick.js

+11-10
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,17 @@
77
/**
88
* @ngdoc directive
99
* @name ngClick
10+
* @deprecated
1011
*
1112
* @description
13+
* <div class="alert alert-danger">
14+
* **DEPRECATION NOTICE**: Beginning with Angular 1.5, this directive is deprecated and by default **disabled**.
15+
* The directive will receive no further support and might be removed from future releases.
16+
* If you need the directive, you can enable it with the {@link ngTouch.$touchProvider $touchProvider#ngClickOverrideEnabled}
17+
* function. We also recommend that you migrate to [FastClick](https://github.com/ftlabs/fastclick).
18+
* To learn more about the 300ms delay, this [Telerik article](http://developer.telerik.com/featured/300-ms-click-delay-ios-8/)
19+
* gives a good overview.
20+
* </div>
1221
* A more powerful replacement for the default ngClick designed to be used on touchscreen
1322
* devices. Most mobile browsers wait about 300ms after a tap-and-release before sending
1423
* the click event. This version handles them immediately, and then prevents the
@@ -40,15 +49,7 @@
4049
</example>
4150
*/
4251

43-
ngTouch.config(['$provide', function($provide) {
44-
$provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
45-
// drop the default ngClick directive
46-
$delegate.shift();
47-
return $delegate;
48-
}]);
49-
}]);
50-
51-
ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
52+
var ngTouchClickDirectiveFactory = ['$parse', '$timeout', '$rootElement',
5253
function($parse, $timeout, $rootElement) {
5354
var TAP_DURATION = 750; // Shorter than 750ms is a tap, longer is a taphold or drag.
5455
var MOVE_TOLERANCE = 12; // 12px seems to work in most mobile browsers.
@@ -292,5 +293,5 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
292293
});
293294

294295
};
295-
}]);
296+
}];
296297

src/ngTouch/touch.js

+101
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
'use strict';
22

3+
/* global ngTouchClickDirectiveFactory: false,
4+
*/
5+
36
/**
47
* @ngdoc module
58
* @name ngTouch
@@ -22,6 +25,104 @@
2225
/* global -ngTouch */
2326
var ngTouch = angular.module('ngTouch', []);
2427

28+
ngTouch.provider('$touch', $TouchProvider);
29+
2530
function nodeName_(element) {
2631
return angular.lowercase(element.nodeName || (element[0] && element[0].nodeName));
2732
}
33+
34+
/**
35+
* @ngdoc provider
36+
* @name $touchProvider
37+
*
38+
* @description
39+
* The `$touchProvider` allows enabling / disabling {@link ngTouch.ngClick ngTouch's ngClick directive}.
40+
*/
41+
$TouchProvider.$inject = ['$provide', '$compileProvider'];
42+
function $TouchProvider($provide, $compileProvider) {
43+
44+
/**
45+
* @ngdoc method
46+
* @name $touchProvider#ngClickOverrideEnabled
47+
*
48+
* @param {boolean=} enabled update the ngClickOverrideEnabled state if provided, otherwise just return the
49+
* current ngClickOverrideEnabled state
50+
* @returns {*} current value if used as getter or itself (chaining) if used as setter
51+
*
52+
* @kind function
53+
*
54+
* @description
55+
* Call this method to enable/disable {@link ngTouch.ngClick ngTouch's ngClick directive}. If enabled,
56+
* the default ngClick directive will be replaced by a version that eliminates the 300ms delay for
57+
* click events on browser for touch-devices.
58+
*
59+
* The default is `false`.
60+
*
61+
*/
62+
var ngClickOverrideEnabled = false;
63+
var ngClickDirectiveAdded = false;
64+
this.ngClickOverrideEnabled = function(enabled) {
65+
if (angular.isDefined(enabled)) {
66+
67+
if (enabled && !ngClickDirectiveAdded) {
68+
ngClickDirectiveAdded = true;
69+
70+
// Use this to identify the correct directive in the delegate
71+
ngTouchClickDirectiveFactory.$$moduleName = 'ngTouch';
72+
$compileProvider.directive('ngClick', ngTouchClickDirectiveFactory);
73+
74+
$provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
75+
if (ngClickOverrideEnabled) {
76+
// drop the default ngClick directive
77+
$delegate.shift();
78+
} else {
79+
// drop the ngTouch ngClick directive if the override has been re-disabled (because
80+
// we cannot de-register added directives)
81+
var i = $delegate.length-1;
82+
while (i >= 0) {
83+
if ($delegate[i].$$moduleName === 'ngTouch') {
84+
$delegate.splice(i, 1);
85+
break;
86+
}
87+
i--;
88+
}
89+
}
90+
91+
return $delegate;
92+
}]);
93+
}
94+
95+
ngClickOverrideEnabled = enabled;
96+
return this;
97+
}
98+
99+
return ngClickOverrideEnabled;
100+
};
101+
102+
/**
103+
* @ngdoc service
104+
* @name $touch
105+
* @kind object
106+
*
107+
* @description
108+
* Provides the {@link ngTouch.$touch#ngClickOverrideEnabled `ngClickOverrideEnabled`} method.
109+
*
110+
*/
111+
this.$get = function() {
112+
return {
113+
/**
114+
* @ngdoc method
115+
* @name $touch#ngClickOverrideEnabled
116+
*
117+
* @returns {*} current value of `ngClickOverrideEnabled` set in the {@link ngTouch.$touchProvider $touchProvider},
118+
* i.e. if {@link ngTouch.ngClick ngTouch's ngClick} directive is enabled.
119+
*
120+
* @kind function
121+
*/
122+
ngClickOverrideEnabled: function() {
123+
return ngClickOverrideEnabled;
124+
}
125+
};
126+
};
127+
128+
}

0 commit comments

Comments
 (0)