Disable double-tap "zoom" option in browser on touch devices - html

I want to disable the double-tap zoom functionality on specified elements in the browser (on touch devices), without disabling all the zoom functionality.
For example: One element can be tapped multiple times for something to happen. This works fine on desktop browsers (as expected), but on touch device browsers, it will zoom in.

Note (as of 2020-08-04): this solution does not appear to work in iOS Safari v12+. I will update this answer and delete this note once I find a clear solution that covers iOS Safari.
CSS-only solution
Add touch-action: manipulation to any element on which you want to disable double tap zoom, like with the following disable-dbl-tap-zoom class:
.disable-dbl-tap-zoom {
touch-action: manipulation;
}
<button>plain button</button>
<button class="disable-dbl-tap-zoom">button with disabled double-tap zoom</button>
<p>A <b>plain</b> paragraph. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.</p>
<p class="disable-dbl-tap-zoom">A paragraph <b>with disabled double-tap zoom</b>. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.</p>
From the touch-action docs (emphasis mine):
manipulation
Enable panning and pinch zoom gestures, but disable additional non-standard gestures such as double-tap to zoom.
This value works on Android and on iOS.

<head>
<title>Site</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
etc...
</head>
I've used that very recently and it works fine on iPad. Haven't tested on Android or other devices (because the website will be displayed on iPad only).

CSS to disable double-tap zoom globally (on any element):
* {
touch-action: manipulation;
}
manipulation
Enable panning and pinch zoom gestures, but disable additional non-standard gestures such as double-tap to zoom.
Thanks Ross, my answer extends his: https://stackoverflow.com/a/53236027/9986657

I know this may be old, but I found a solution that worked perfectly for me. No need for crazy meta tags and stopping content zooming.
I'm not 100% sure how cross-device it is, but it worked exactly how I wanted to.
$('.no-zoom').bind('touchend', function(e) {
e.preventDefault();
// Add your code here.
$(this).click();
// This line still calls the standard click event, in case the user needs to interact with the element that is being clicked on, but still avoids zooming in cases of double clicking.
})
This will simply disable the normal tapping function, and then call a standard click event again. This prevents the mobile device from zooming, but otherwise functions as normal.
EDIT: This has now been time-tested and running in a couple live apps. Seems to be 100% cross-browser and platform. The above code should work as a copy-paste solution for most cases, unless you want custom behavior before the click event.

I just wanted to answer my question properly as some people do not read the comments below an answer. So here it is:
(function($) {
$.fn.nodoubletapzoom = function() {
$(this).bind('touchstart', function preventZoom(e) {
var t2 = e.timeStamp
, t1 = $(this).data('lastTouch') || t2
, dt = t2 - t1
, fingers = e.originalEvent.touches.length;
$(this).data('lastTouch', t2);
if (!dt || dt > 500 || fingers > 1) return; // not double-tap
e.preventDefault(); // double tap - prevent the zoom
// also synthesize click events we just swallowed up
$(this).trigger('click').trigger('click');
});
};
})(jQuery);
I did not write this, i just modified it. I found the iOS-only version here: https://gist.github.com/2047491 (thanks Kablam)

If you need a version that works without jQuery, I modified Wouter Konecny's answer (which was also created by modifying this gist by Johan Sundström) to use vanilla JavaScript.
function preventZoom(e) {
var t2 = e.timeStamp;
var t1 = e.currentTarget.dataset.lastTouch || t2;
var dt = t2 - t1;
var fingers = e.touches.length;
e.currentTarget.dataset.lastTouch = t2;
if (!dt || dt > 500 || fingers > 1) return; // not double-tap
e.preventDefault();
e.target.click();
}
Then add an event handler on touchstart that calls this function:
myButton.addEventListener('touchstart', preventZoom);

You should set the css property touch-action to none as described in this other answer https://stackoverflow.com/a/42288386/1128216
.disable-doubletap-to-zoom {
touch-action: none;
}

* {
-ms-touch-action: manipulation;
touch-action: manipulation;
}
Disable double tap to zoom on touch screens. Internet explorer included.

Simple prevent the default behavior of click, dblclick or touchend events will disable the zoom functionality.
If you have already a callback on one of this events just call a event.preventDefault().

If you only want to prevent double click zoom across all devices, try setting the dblclick event listener of the button to preventDefault(). This worked for me!
edit: typo in 'dblclick'
const button = document.querySelector('#button');
button.addEventListener('dblclick', function(el) {
el.preventDefault();
});
<button id="button"> No double click zoom here</button>

If there is anyone like me who is experiencing this issue using Vue.js,
simply adding .prevent will do the trick: #click.prevent="someAction"

Disable double tap zoom on mobile (2023 IOS Safari solution):
I found that using the meta tag method was not a viable solution for mobile safari browsers. Here is the solution that worked for me.
working solution:
.selector {
touch-action: manipulation;
}
by simply adding a touch-action of manipulation all buttons with the following rule applied will not zoom on consecutive clicks of the button.
example website: calculator app

This will prevent double tap zoom on elements in 'body' this can be changed to any other selector
$('body').bind('touchstart', function preventZoom(e){
var t2 = e.timeStamp;
var t1 = $(this).data('lastTouch') || t2;
var dt = t2 - t1;
var fingers = e.originalEvent.touches.length;
$(this).data('lastTouch', t2);
if (!dt || dt > 500 || fingers > 1){
return; // not double-tap
}
e.preventDefault(); // double tap - prevent the zoom
// also synthesize click events we just swallowed up
$(e.target).trigger('click');
});
But this also prevented my click event from triggering when clicked multiple times so i had to bind a another event to trigger the events on multiple clicks
$('.selector').bind('touchstart click', preventZoom(e) {
e.stopPropagation(); //stops propagation
if(e.type == "touchstart") {
// Handle touchstart event.
} else if(e.type == "click") {
// Handle click event.
}
});
On touchstart i added the code to prevent the zoom and trigger a click.
$('.selector').bind('touchstart, click', function preventZoom(e){
e.stopPropagation(); //stops propagation
if(e.type == "touchstart") {
// Handle touchstart event.
var t2 = e.timeStamp;
var t1 = $(this).data('lastTouch') || t2;
var dt = t2 - t1;
var fingers = e.originalEvent.touches.length;
$(this).data('lastTouch', t2);
if (!dt || dt > 500 || fingers > 1){
return; // not double-tap
}
e.preventDefault(); // double tap - prevent the zoom
// also synthesize click events we just swallowed up
$(e.target).trigger('click');
} else if(e.type == "click") {
// Handle click event.
"Put your events for click and touchstart here"
}
});

Here's a variation that currently, as of 2022, does the trick on most device versions; Android / iOS.
Note that for example iOS 14+ zooms in on any text input fields that has a font-size of less than 1rem 16px, which also quite senior pros seem to have missed.
A vanilla javascript example - that can be improved further - for example with logic to allow normal behavior scenarios too - so for your experimentation.
document.getElementById('selectorid').addEventListener('touchend' || 'dblclick', event => {
event.preventDefault();
event.stopImmediatePropagation();
}, {
passive: false
});
Here's a more covering example for testing purposes to see if it achieves wished results. This one affects all the elements on the page inherited in the DOM.
/* For testing purposes, overrides events that may trigger a "zoom"; note that this may cause other unexpected behavior */
window.addEventListener('touchmove' || 'touchdowm' || 'touchend' || 'mousedown' || 'dblclick', event => {
event.preventDefault();
event.stopImmediatePropagation();
}, {
passive: false
});
Here's some simple CSS, for overriding test purposes - try it out on the page and you may expect a remedy clue if form fields are what's bugging. Although the minimum size of 16px is actually quite wishfully intentional for accesibillity concerns. Note that the "!important" flag isn't considered good practice to manifest in a production deploy.
/* CSS to test prevention of zoom when interacting with input fields */
input[type=text] {
font-size: 1rem !important;
}

most of the coding above doesn't work unfortunately
these simple lines will do it
document.addEventListener('dblclick', function(event) {
event.preventDefault();
}, { passive: false });

I assume that I do have a <div> input container area with text, sliders and buttons in it, and want to inhibit accidental double-taps in that <div>.
The following does not inhibit zooming on the input area, and it does not relate to double-tap and zooming outside my <div> area. There are variations depending on the browser app.
I just tried it.
(1) For Safari on iOS, and Chrome on Android, and is the preferred method. Works except for Internet app on Samsung, where it disables double-taps not on the full <div>, but at least on elements that handle taps. It returns return false, with exception on text and range inputs.
$('selector of <div> input area').on('touchend',disabledoubletap);
function disabledoubletap(ev) {
var preventok=$(ev.target).is('input[type=text],input[type=range]');
if(preventok==false) return false;
}
(2) Optionally for built-in Internet app on Android (5.1, Samsung), inhibits double-taps on the <div>, but inhibits zooming on the <div>:
$('selector of <div> input area').on('touchstart touchend',disabledoubletap);
(3) For Chrome on Android 5.1, disables double-tap at all, does not inhibit zooming, and does nothing about double-tap in the other browsers.
The double-tap-inhibiting of the <meta name="viewport" ...> is irritating, because <meta name="viewport" ...> seems good practice.
<meta name="viewport" content="width=device-width, initial-scale=1,
maximum-scale=5, user-scalable=yes">

Using CSS touch-events: none
Completly takes out all the touch events. Just leaving this here in case someone also has this problems, took me 2 hours to find this solution and it's only one line of css.
https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action

Here we go
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

Related

Sometimes links are not clickable [duplicate]

I have a link button inside a <td> which I have to disable. This works on IE but not working in Firefox and Chrome.
I tried all the following but not working on Firefox (using 1.4.2 js):
$(".myLink").attr('disabled', 'disabled');
$(".myLink").attr('disabled', true);
$(".myLink").attr('disabled', 'true');
Note - I cannot de-register the click function for the anchor tag as it is registered dynamically. AND I HAVE TO SHOW THE LINK IN DISABLED MODE.
You can't disable a link (in a portable way). You can use one of these techniques (each one with its own benefits and disadvantages).
CSS way
This should be the right way (but see later) to do it when most of browsers will support it:
a.disabled {
pointer-events: none;
}
It's what, for example, Bootstrap 3.x does. Currently (2016) it's well supported only by Chrome, FireFox and Opera (19+). Internet Explorer started to support this from version 11 but not for links however it's available in an outer element like:
span.disable-links {
pointer-events: none;
}
With:
<span class="disable-links">...</span>
Workaround
We, probably, need to define a CSS class for pointer-events: none but what if we reuse the disabled attribute instead of a CSS class? Strictly speaking disabled is not supported for <a> but browsers won't complain for unknown attributes. Using the disabled attribute IE will ignore pointer-events but it will honor IE specific disabled attribute; other CSS compliant browsers will ignore unknown disabled attribute and honor pointer-events. Easier to write than to explain:
a[disabled] {
pointer-events: none;
}
Another option for IE 11 is to set display of link elements to block or inline-block:
<a style="pointer-events: none; display: inline-block;" href="#">...</a>
Note that this may be a portable solution if you need to support IE (and you can change your HTML) but...
All this said please note that pointer-events disables only...pointer events. Links will still be navigable through keyboard then you also need to apply one of the other techniques described here.
Focus
In conjunction with above described CSS technique you may use tabindex in a non-standard way to prevent an element to be focused:
...
I never checked its compatibility with many browsers then you may want to test it by yourself before using this. It has the advantage to work without JavaScript. Unfortunately (but obviously) tabindex cannot be changed from CSS.
Intercept clicks
Use a href to a JavaScript function, check for the condition (or the disabled attribute itself) and do nothing in case.
$("td > a").on("click", function(event){
if ($(this).is("[disabled]")) {
event.preventDefault();
}
});
To disable links do this:
$("td > a").attr("disabled", "disabled");
To re-enable them:
$("td > a").removeAttr("disabled");
If you want instead of .is("[disabled]") you may use .attr("disabled") != undefined (jQuery 1.6+ will always return undefined when the attribute is not set) but is() is much more clear (thanks to Dave Stewart for this tip). Please note here I'm using the disabled attribute in a non-standard way, if you care about this then replace attribute with a class and replace .is("[disabled]") with .hasClass("disabled") (adding and removing with addClass() and removeClass()).
Zoltán Tamási noted in a comment that "in some cases the click event is already bound to some "real" function (for example using knockoutjs) In that case the event handler ordering can cause some troubles. Hence I implemented disabled links by binding a return false handler to the link's touchstart, mousedown and keydown events. It has some drawbacks (it will prevent touch scrolling started on the link)" but handling keyboard events also has the benefit to prevent keyboard navigation.
Note that if href isn't cleared it's possible for the user to manually visit that page.
Clear the link
Clear the href attribute. With this code you do not add an event handler but you change the link itself. Use this code to disable links:
$("td > a").each(function() {
this.data("href", this.attr("href"))
.attr("href", "javascript:void(0)")
.attr("disabled", "disabled");
});
And this one to re-enable them:
$("td > a").each(function() {
this.attr("href", this.data("href")).removeAttr("disabled");
});
Personally I do not like this solution very much (if you do not have to do more with disabled links) but it may be more compatible because of various way to follow a link.
Fake click handler
Add/remove an onclick function where you return false, link won't be followed. To disable links:
$("td > a").attr("disabled", "disabled").on("click", function() {
return false;
});
To re-enable them:
$("td > a").removeAttr("disabled").off("click");
I do not think there is a reason to prefer this solution instead of the first one.
Styling
Styling is even more simple, whatever solution you're using to disable the link we did add a disabled attribute so you can use following CSS rule:
a[disabled] {
color: gray;
}
If you're using a class instead of attribute:
a.disabled {
color: gray;
}
If you're using an UI framework you may see that disabled links aren't styled properly. Bootstrap 3.x, for example, handles this scenario and button is correctly styled both with disabled attribute and with .disabled class. If, instead, you're clearing the link (or using one of the others JavaScript techniques) you must also handle styling because an <a> without href is still painted as enabled.
Accessible Rich Internet Applications (ARIA)
Do not forget to also include an attribute aria-disabled="true" together with disabled attribute/class.
Got the fix in css.
td.disabledAnchor a{
pointer-events: none !important;
cursor: default;
color:Gray;
}
Above css when applied to the anchor tag will disable the click event.
For details checkout this link
Thanks to everyone that posted solutions (especially #AdrianoRepetti), I combined multiple approaches to provide some more advanced disabled functionality (and it works cross browser). The code is below (both ES2015 and coffeescript based on your preference).
This provides for multiple levels of defense so that Anchors marked as disable actually behave as such.
Using this approach, you get an anchor that you cannot:
click
tab to and hit return
tabbing to it will move focus to the next focusable element
it is aware if the anchor is subsequently enabled
How to
Include this css, as it is the first line of defense. This assumes the selector you use is a.disabled
a.disabled {
pointer-events: none;
cursor: default;
}
Next, instantiate this class on ready (with optional selector):
new AnchorDisabler()
ES2015 Class
npm install -S key.js
import {Key, Keycodes} from 'key.js'
export default class AnchorDisabler {
constructor (config = { selector: 'a.disabled' }) {
this.config = config
$(this.config.selector)
.click((ev) => this.onClick(ev))
.keyup((ev) => this.onKeyup(ev))
.focus((ev) => this.onFocus(ev))
}
isStillDisabled (ev) {
// since disabled can be a class or an attribute, and it can be dynamically removed, always recheck on a watched event
let target = $(ev.target)
if (target.hasClass('disabled') || target.prop('disabled') == 'disabled') {
return true
}
else {
return false
}
}
onFocus (ev) {
// if an attempt is made to focus on a disabled element, just move it along to the next focusable one.
if (!this.isStillDisabled(ev)) {
return
}
let focusables = $(':focusable')
if (!focusables) {
return
}
let current = focusables.index(ev.target)
let next = null
if (focusables.eq(current + 1).length) {
next = focusables.eq(current + 1)
} else {
next = focusables.eq(0)
}
if (next) {
next.focus()
}
}
onClick (ev) {
// disabled could be dynamically removed
if (!this.isStillDisabled(ev)) {
return
}
ev.preventDefault()
return false
}
onKeyup (ev) {
// We are only interested in disabling Enter so get out fast
if (Key.isNot(ev, Keycodes.ENTER)) {
return
}
// disabled could be dynamically removed
if (!this.isStillDisabled(ev)) {
return
}
ev.preventDefault()
return false
}
}
Coffescript class:
class AnchorDisabler
constructor: (selector = 'a.disabled') ->
$(selector).click(#onClick).keyup(#onKeyup).focus(#onFocus)
isStillDisabled: (ev) =>
### since disabled can be a class or an attribute, and it can be dynamically removed, always recheck on a watched event ###
target = $(ev.target)
return true if target.hasClass('disabled')
return true if target.attr('disabled') is 'disabled'
return false
onFocus: (ev) =>
### if an attempt is made to focus on a disabled element, just move it along to the next focusable one. ###
return unless #isStillDisabled(ev)
focusables = $(':focusable')
return unless focusables
current = focusables.index(ev.target)
next = (if focusables.eq(current + 1).length then focusables.eq(current + 1) else focusables.eq(0))
next.focus() if next
onClick: (ev) =>
# disabled could be dynamically removed
return unless #isStillDisabled(ev)
ev.preventDefault()
return false
onKeyup: (ev) =>
# 13 is the js key code for Enter, we are only interested in disabling that so get out fast
code = ev.keyCode or ev.which
return unless code is 13
# disabled could be dynamically removed
return unless #isStillDisabled(ev)
ev.preventDefault()
return false
Try the element:
$(td).find('a').attr('disabled', 'disabled');
Disabling a link works for me in Chrome: http://jsfiddle.net/KeesCBakker/LGYpz/.
Firefox doesn't seem to play nice. This example works:
<a id="a1" href="http://www.google.com">Google 1</a>
<a id="a2" href="http://www.google.com">Google 2</a>
$('#a1').attr('disabled', 'disabled');
$(document).on('click', 'a', function(e) {
if ($(this).attr('disabled') == 'disabled') {
e.preventDefault();
}
});
Note: added a 'live' statement for future disabled / enabled links.
Note2: changed 'live' into 'on'.
Bootstrap 4.1 provides a class named disabled and aria-disabled="true" attribute.
example"
<a href="#"
class="btn btn-primary btn-lg disabled"
tabindex="-1"
role="button" aria-disabled="true"
>
Primary link
</a>
More is on getbootstrap.com
So if you want to make it dynamically, and you don't want to care if it is button or ancor than
in JS script you need something like that
let $btn=$('.myClass');
$btn.attr('disabled', true);
if ($btn[0].tagName == 'A'){
$btn.off();
$btn.addClass('disabled');
$btn.attr('aria-disabled', true);
}
But be carefull
The solution only works on links with classes btn btn-link.
Sometimes bootstrap recommends using card-link class, in this case solution will not work.
Just add a css property:
<style>
a {
pointer-events: none;
}
</style>
Doing so you can disable the anchor tag.
I've ended up with the solution below, which can work with either an attribute, <a href="..." disabled="disabled">, or a class <a href="..." class="disabled">:
CSS Styles:
a[disabled=disabled], a.disabled {
color: gray;
cursor: default;
}
a[disabled=disabled]:hover, a.disabled:hover {
text-decoration: none;
}
Javascript (in jQuery ready):
$("a[disabled], a.disabled").on("click", function(e){
var $this = $(this);
if ($this.is("[disabled=disabled]") || $this.hasClass("disabled"))
e.preventDefault();
})
In Razor (.cshtml) you can do:
#{
var isDisabled = true;
}
Home
You can disable the HTML link as given below:
<style>
.disabled-link {
pointer-events: none;
}
</style>
Google.com
You can use inline JavaScript:
Google.com
you cannot disable a link, if you want that click event should not fire then simply Remove the action from that link.
$(td).find('a').attr('href', '');
For More Info :- Elements that can be Disabled
I would do something like
$('td').find('a').each(function(){
$(this).addClass('disabled-link');
});
$('.disabled-link').on('click', false);
something like this should work. You add a class for links you want to have disabled and then you return false when someone click them. To enable them just remove the class.
To disable link to access another page on touch device:
if (control == false)
document.getElementById('id_link').setAttribute('href', '#');
else
document.getElementById('id_link').setAttribute('href', 'page/link.html');
end if;
I would suggest turning the link into a button and using the 'disabled' attribute. You can see this issue to check how to convert a link to a button: How to create an HTML button that acts like a link
You can use this to disabled the Hyperlink of asp.net or link buttons in html.
$("td > a").attr("disabled", "disabled").on("click", function() {
return false;
});
There is one other possible way, and the one that I like best. Basically it's the same way lightbox disables a whole page, by placing a div and fiddling with z-index. Here is relevant snippets from a project of mine. This works in all browsers!!!!!
Javascript (jQuery):
var windowResizer = function(){
var offset = $('#back').offset();
var buttontop = offset.top;
var buttonleft = offset.left;
$('#backdisabler').css({'top':buttontop,'left':buttonleft,'visibility':'visible'});
offset = $('#next').offset();
buttontop = offset.top;
buttonleft = offset.left;
$('#nextdisabler').css({'top':buttontop,'left':buttonleft,'visibility':'visible'});
}
$(document).ready(function() {
$(window).resize(function() {
setTimeout(function() {
windowResizer();
}, 5); //when the maximize/restore buttons are pressed, we have to wait or it will fire to fast
});
});
and in html
<img src="images/icons/back.png" style="height: 50px; width: 50px" />
<img src="images/icons/next.png" style="height: 50px; width: 50px" />
<img id="backdisabler" src="images/icons/disabled.png" style="visibility: hidden; position: absolute; padding: 5px; height: 62px; width: 62px; z-index: 9000"/>
<img id="nextdisabler" src="images/icons/disabled.png" style="visibility: hidden; position: absolute; padding: 5px; height: 62px; width: 62px; z-index: 9000"/>
So the resizer finds the anchor's (the images are just arrows) locations and places the disabler on top. The disabler's image is a translucent grey square (change the width/height of the disablers in the html to match your link) to show that it is disabled. The floating allows the page to resize dynamically, and the disablers will follow suit in windowResizer(). You can find suitable images through google. I have placed the relevant css inline for simplicity.
then based on some condition,
$('#backdisabler').css({'visibility':'hidden'});
$('#nextdisabler').css({'visibility':'visible'});
I think a lot of these are over thinking. Add a class of whatever you want, like disabled_link. Then make the css have .disabled_link { display: none }
Boom now the user can't see the link so you won't have to worry about them clicking it. If they do something to satisfy the link being clickable, simply remove the class with jQuery: $("a.disabled_link").removeClass("super_disabled"). Boom done!

touchstart and touchend events in ionic 3

I'm looking for a separate event handler in Ionic 3 for starting and ending a touch on an HTML element on a mobile app.
I found many related and solved questions, but none for Ionic 3, which currently only seems to support "tap, press, pan, swipe, rotate, and pinch" (https://ionicframework.com/docs/components/#gestures).
And none of these seem to provide a "handler" at the start, but only at the end. I see that then they do give the data of the touch duration (deltaTime), but by that point it's no use for my purposes.
For more context, what I want is to clear a related timeout in the exact moment when the screen is first touched on an element, and then see whether or not this touch on the same specific element ends within a certain time (e.g. 250 ms, so that it can be evaluated as a "tap").
For example something like this:
JS:
timeout_1 = setTimeout(function() {
// do something if timeout_1 not cleared by touch start
}, 4000);
touched(event) {
clearTimeout(timeout_1);
touching_x = true
timeout_2 = setTimeout(function() {
touching_x = false
// store event details and do other things if timeout_2 not cleared by touch end
}, 250);
}
touch_ended(event) {
if (touching_x==true) {
clearTimeout(timeout_2);
// store event details and do some other things
}
}
HTML:
<button ion-button type="button" (button_touch_started) = "touched($event)" (button_touch_ended) = "touch_ended($event)">Touch button</button>
High precision (down to ms) would be important especially for the touch start time.
Any advice is appreciated.
Html
Try either div or button
<div style="height:100%;width:100%" (touchstart)="touchstart($event)" (touchend)="touchend($event)">
</div>
<button ion-button large primary (touchstart)="touchstart($event);">touchstart</button>
<button ion-button large primary (touchend)="touchend($event);">touchend</button>
Ts
touchstart(event){
console.log(event);
}
touchend(event){
console.log(event);
}

Disabled button is clickable on Edge browser

I have problem with Edge browser. In my web site I have buttons with span tags inside them. In this span tags I bind text and icons. So far I had no problem but on Edge browser it is possible to click on disabled buttons. After investigating problem I found out that, when button contains span tags inside, it is possible to click on button. Here is how it looks on my web site:
<button id="btnRefresh" type="button" class="btn btn-primary" ng-click="refresh()" ng-disabled="performingAction">
<span ng-class="performingAction && action == 'refresh' ? 'fa fa-cog fa-spin' :'fa fa-refresh'"></span>
<span>{{ refresh }}</span>
</button>
Here is example to testing:
<button type="button" disabled="disabled" onclick='alert("test");'>
<span>Click me!</span>
</button>
One option would be to hide buttons instead of disabling, but I prefer to disable them. Please suggest solution to over come this issue.
Just set
pointer-events: none;
for disabled buttons.
Here's CSS to disable all disabled elements everywhere:
*[disabled] {
pointer-events: none !important;
}
pointer-events documentation
This is a bug in Microsoft Edge. Disabled buttons accept clicks if they contain any HTML elements (i.e. if they contain anything else than just text).
Reported multiple times via Microsoft Connect:
Event bubbles from child element into element (by SO user Ryan Joy)
Bootstrap/Jquery disabled buttons generate click events and show tooltips even disabled
The bug was still present in Build 10565 (16 October 2015).
It was fixed in the November update, Build 10586.
A possible (but ugly) workaround is to call some Javascript in onclick for every button, which then checks if the button is disabled and returns false (thus suppressing the click event).
One work around I've come up with using angularjs is inspired by Ben Nadel's blog here
So for example:
angular.module('myModule').directive(
"span",
function spanDirective() {
return ({
link: function (scope, element, attributes) {
element.bind('click', function (e) {
if (e.target.parentNode.parentNode.disabled || e.target.parentNode.disabled) {
e.stopPropagation();
}
})
},
restrict: "E",
});
}
);
Since you're not always going to be using a span element and probably don't want to create a new directive for every element type, a more general workaround would be to decorate the ngClick directive to prevent the event from reaching the real ngClick's internal event handler when the event is fired on a disabled element.
var yourAppModule = angular.module('myApp');
// ...
yourAppModule.config(['$provide', function($provide) {
$provide.decorator('ngClickDirective', ['$delegate', '$window', function($delegate, $window) {
var isEdge = /windows.+edge\//i.test($window.navigator.userAgent);
if (isEdge) {
var directiveConfig = $delegate[0];
var originalCompileFn = directiveConfig.compile;
directiveConfig.compile = function() {
var origLinkFn = originalCompileFn.apply(directiveConfig, arguments);
// Register a click event handler that will execute before the one the original link
// function registers so we can stop the event.
return function linkFn(scope, element) {
element.on('click', function(event) {
if (event.currentTarget && event.currentTarget.disabled) {
event.preventDefault();
event.stopPropagation();
event.stopImmediatePropagation();
}
});
return origLinkFn.apply(null, arguments);
};
};
}
return $delegate;
}]);
}]);

Workaround for file input label click (Firefox)

<label for="input">Label</label><input type="file" id="input"/>
In Firefox 7 it is not possible to trigger the open file dialog by clicking on the label.
This SO question is very similar but that's green checked with it's a bug in FF. I'm looking for a workaround.
Any ideas?
thank you for this q&a... helped me out.
my variation of #marten-wikstrom's solution:
if($.browser.mozilla) {
$(document).on('click', 'label', function(e) {
if(e.currentTarget === this && e.target.nodeName !== 'INPUT') {
$(this.control).click();
}
});
}
notes
using document.ready ($(function() {...});) is unnecessary, in either solution. jQuery.fn.live takes care of that in #marten-wikstrom's case; explicitly binding to document does in my example.
using jQuery.fn.on... current recommended binding technique.
added the !== 'INPUT' check to ensure execution does not get caught in a loop here:
<label>
<input type="file">
</label>
(since the file field click will bubble back up to the label)
change event.target check to event.currentTarget, allowing for initial click on the <em> in:
<label for="field">click <em>here</em></label>
using the label element's control attribute for cleaner, simpler, spec-base form field association.
I came up with a feasible workaround:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
$("label").click(function () {
$("#input").click();
});
});
</script>
<label for="input">Label</label><input type="file" id="input"/>
Quite strange that FF allows you to simulate a click on a file input. I thought that was considered a security risk...
UPDATE: This is a generic workaround:
<script type="text/javascript">
$(function () {
if ($.browser.mozilla) {
$("label").live("click", function (event) {
if (event.target == this) {
$("#" + $(this).attr("for")).extend($("input", this)).first().click();
}
});
}
});
</script>
A couple problems arise when using the jQuery browser detection, most notably the anti-pattern of using browser detection rather than feature detection, in addition to the fact that 1.9+ doesn't provide that functionality.
Perhaps, then, the solution I arrived at is a bit hypocritical, but it worked well and seems to adhere to most best practices today.
First, ensure you're using Paul Irish's conditional classes. Then, use something like:
if($("html").hasClass("ie")) {
$("label").click();
} else {
$("input").click();
}
Otherwise, I found the event would be double-fired in browsers such as Chrome. This solution seemed elegant enough.
The file-selection dialog can be triggered in all browsers by the click() event. An unobtrusive solution to this problem could look like that:
$('label')
.attr('for', null)
.click(function() {
$('#input').click();
});
Removing the for attribute is important since other browsers (e.g. Chrome, IE) will still ratify it and show the dialog twice.
I tested it in Chrome 25, Firefox 19 and IE 9 and works like a charm.
It seems to be fixed in FF 23, so browser detection becomes hazardous and leads to double system dialogs ;(
You can add another test to restrict the fix to FF version prior to version 23:
if(parseInt(navigator.buildID,10) < 20130714000000){
//DO THE FIX
}
It's quite ugly, but this fix will be removed as soon as old the version of FF will have disappeared.
A work around when you don't need/want to have the input box (like image upload) is to use opacity: 0 in the element and use pointer-events: none; in the label.
The solution is really design specific but maybe should work for someone who comes to this. (until now the bug doesn't been fixed)
http://codepen.io/octavioamu/pen/ByOQBE
you can dispatch the event from any event to the type=file input if you want
make the input display:none and visibility:hidden, and then dispatch the event from,
say, the click|touch of an image ...
<img id="customImg" src="file.ext"/>
<input id="fileLoader" type="file" style="display:none;visibility:hidden"/>
<script>
customImg.addEventListener(customImg.ontouchstart?'touchstart':'click', function(e){
var evt = document.createEvent('HTMLEvents');
evt.initEvent('click',false,true);
fileLoader.dispatchEvent(evt);
},false);
</script>
Using the answer of Corey above in a React environment I had to do the following:
(Firefox check is based on: How to detect Safari, Chrome, IE, Firefox and Opera browser?)
const ReactFileInputButton = ({ onClick }) => {
const isFirefox = typeof InstallTrigger !== 'undefined';
const handleClick = isFirefox ? (e) => {
e.currentTarget.control.click();
} : undefined;
const handleFileSelect = (e) => {
if (e.target.files && e.target.files[0]) {
onClick({ file: e.target.files[0] });
}
}
return (
<>
<input type="file" id="file" onChange={handleFileSelect} />
<label htmlFor="file" onClick={handleClick}>
Select file
</label>
</>
);
};
Reverse the order of the label and input elements. iow, put the label element after the input element.
Try this code
<img id="uploadPreview" style="width: 100px; height: 100px;"
onclick="document.getElementById('uploadImage').click(event);" />
<input id="uploadImage" type="file" name="myPhoto" onchange="PreviewImage();" />
<script type="text/javascript">
function PreviewImage() {
var oFReader = new FileReader();
oFReader.readAsDataURL(document.getElementById("uploadImage").files[0]);
oFReader.onload = function (oFREvent) {
document.getElementById("uploadPreview").src = oFREvent.target.result;
};
};
</script>

disable text drag and drop

There is a common feature of modern browsers where a user can select some text and drag it to an input field. Within the same field it causes moving of text, between different fields it does copying.
How do I disable that? If there is no portable way, I am mostly interested in firefox. This is an intranet webapp, so I am also interested in modifying the browser/getting a plugin to do this. Maybe some system-level settings (I`m on windows XP)?
I need to keep the default select-copy-paste functionality.
The background is I have multiple-field data entry forms, and users often drag something by mistake.
For archival purposes:
<body ondragstart="return false" draggable="false"
ondragenter="event.dataTransfer.dropEffect='none'; event.stopPropagation(); event.preventDefault();"
ondragover="event.dataTransfer.dropEffect='none';event.stopPropagation(); event.preventDefault();"
ondrop="event.dataTransfer.dropEffect='none';event.stopPropagation(); event.preventDefault();"
>
does what I wanted. You can add the ondrag* handlers to form elements, too, like <input ondragenter=...>
reference url: https://developer.mozilla.org/En/DragDrop/Drag_Operations
This thing works.....Try it.
<BODY ondragstart="return false;" ondrop="return false;">
hope it helps. Thanks
This code will work in all versions of Mozilla and IE.
function preventDrag(event)
{
if(event.type=='dragenter' || event.type=='dragover' || //if drag over event -- allows for drop event to be captured, in case default for this is to not allow drag over target
event.type=='drop') //prevent text dragging -- IE and new Mozilla (like Firefox 3.5+)
{
if(event.stopPropagation) //(Mozilla)
{
event.preventDefault();
event.stopPropagation(); //prevent drag operation from bubbling up and causing text to be modified on old Mozilla (before Firefox 3.5, which doesn't have drop event -- this avoids having to capture old dragdrop event)
}
return false; //(IE)
}
}
//attach event listeners after page has loaded
window.onload=function()
{
var myTextInput = document.getElementById('textInput'); //target any DOM element here
if(myTextInput.addEventListener) //(Mozilla)
{
myTextInput.addEventListener('dragenter', handleEvents, true); //precursor for drop event
myTextInput.addEventListener('dragover', handleEvents, true); //precursor for drop event
myTextInput.addEventListener('drop', preventDrag, true);
}
else if (myTextInput.attachEvent) //(IE)
{
myTextInput.attachEvent('ondragenter', preventDrag);
myTextInput.attachEvent('ondragover', preventDrag);
myTextInput.attachEvent('ondrop', preventDrag);
}
}
add the following to your field tags:
#ondragstart is for IE, onmousedown is for firefox
ondragstart="return false" onmousedown="return false"
ondraggesture is supported by older versions of Firefox instead of ondragstart.
Use the following code
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("Text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
and:
<input type="text" ondrop="drop(event)" ondragover="allowDrop(event)">
See: http://jsfiddle.net/zLYGF/25/
You can use :focus attribute to recognize over what your mouse is:
if(document.activeElement.tagName == "INPUT"||document.activeElement.tagName == "TEXTAREA"){
event.preventDefault()
return
}