touchstart and touchend in iOS - javascript

guys. I have problem.
I have button event listener (touchstart). When button is clicked, it moves away and click actually happen on coordinates based on touchend. In android it works fine. Problem is with iOS. Button movers, but click happen instantly. I think they actually trigger click when touchstart happen. How to solve it? I can not simulate click by JavaScript, because button is over iframe from another source.
There is my sample code.
function adTr_triggerButton() {
if (adTr_button.classList.contains('trigger')) {
adTr_button.classList.remove('trigger');
console.log('Triggering button...');
} else {
adTr_button.classList.add('trigger');
console.log('Triggering stopped!');
}
}
adTr_button.addEventListener('touchstart', function() {
adTr_triggerButton();
});
I want this to work same as in Android

Related

Javascript preventDefault() not working in Safari

I am working on an application using javascript and I want to get mouse events. To stop the options that appear when right clicking I use the preventDefault() function and it works in Firefox and Chrome but it doesn't work in Safari. This is my code:
document.querySelector("#GL-Surface").addEventListener("mousedown", function(e) {
e.preventDefault();
/* Handle mouse events */
});
From an other question I got that you should return false; but this still doesn't work. preventDefault() however works in Safari when it is used in keyboard inputs. So how can I prevent the default actions for mouse events in Safari?
To target right click events, use contextmenu rather than mousedown.
document.querySelector("#GL-Surface").addEventListener("contextmenu", function(e) {
e.preventDefault();
});
Note that the options that appear on right click do appear only when the right click button is released, so I don't think mousedown is at all suitable here.

dropdown menu not working on mobile, document click not triggered [duplicate]

I've got a sub-nav that works using jquery - A user clicks on the top level list item, for instance 'services' which triggers the dropdown. The dropdown toggles via clicking the 'service' link. I've made it so a user can click anywhere on the screen to toggle the dropdown to a closed state. But as the site is responsive i want the user to be able to click (touch) anywhere on the screen to close the dropdown but my problem is that it's not working on the touch devices.
My code ive setup for the document click is:
$(document).click(function(event) {
if ( $(".children").is(":visible")) {
$("ul.children").slideUp('slow');
}
});
I'm assuming document.click might not work on touch devices, and if not, what work-around is there to achieve the same effect?
Thanks
Update! In modern browsers, the click event will be fired for a tap, so you don't need to add extra touchstart or touchend events as click should suffice.
This previous answer worked for a time with browsers that thought a tap was special. It originally included a "touch" event that actually was never standardised.
Unless you have a problem with:
$(document).on('click', function () { ... });
There is no need to change anything!
Previous information, updated to remove touch...
To trigger the function with click or touch, you could change this:
$(document).click( function () {
To this:
$(document).on('click touchstart', function () {
The touchstart event fires as soon as an element is touched, so it may be more appropriate to use touchend depending on your circumstances.
touchstart or touchend are not good, because if you scroll the page, the device do stuff.
So, if I want close a window with tap or click outside the element, and scroll the window, I've done:
$(document).on('touchstart', function() {
documentClick = true;
});
$(document).on('touchmove', function() {
documentClick = false;
});
$(document).on('click touchend', function(event) {
if (event.type == "click") documentClick = true;
if (documentClick){
doStuff();
}
});
can you use jqTouch or jquery mobile ? there it's much easier to handle touch events.
If not then you need to simulate click on touch device, follow this articles:
iphone-touch-events-in-javascript
A touch demo
More in this thread
To apply it everywhere, you could do something like
$('body').on('click', function() {
if($('.children').is(':visible')) {
$('ul.children').slideUp('slow');
}
});
As stated above, using 'click touchstart' will get the desired result. If you console.log(e) your clicks though, you may find that when jquery recognizes touch as a click - you will get 2 actions from click and touchstart. The solution bellow worked for me.
//if its a mobile device use 'touchstart'
if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
deviceEventType = 'touchstart'
} else {
//If its not a mobile device use 'click'
deviceEventType = 'click'
}
$(document).on(specialEventType, function(e){
//code here
});
the approved answer does not include the essential return false to prevent touchstart from calling click if click is implemented which will result in running the handler twoce.
do:
$(btn).on('click touchstart', e => {
your code ...
return false;
});

Responding to touchstart and mousedown in desktop and mobile, without sniffing

So, I have a problem. I want to respond to a user pressing the mouse button (on desktop) or touching a div (on mobile). I'm trying to be compatile with evergreen browsers. This is what I tried so far:
listen only to mouseDown event. This works on desktop but doesn't work in mobile if the user is dragging. I want the handler to be called as soon as the user touches the screen, no matter if they're moving their finger in the process.
listen only to touchStart event. This works on mobile and desktop, except for Edge and Safari desktop, which don't support touch events.
listen to both, then preventDefault. This causes a double handler call on Chrome mobile. It seems that touch events are passive to allow uninterrupted scrolling on mobile Chrome, so preventDefualt has no effect on them . What I get is a warning message saying "[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080" in the console, preventDefault is ignored and my event is called twice.
Obviously this can be solved by sniffing touch events, but the net is full of self-righteous rants on how one has to be device-agnostic and that it's dangerous to detect touch events before the user interacted.
So I guess that the question is: is there a way to do what I want to do without sniffing for touch events?
Below my sample React code:
function handler(e) {
console.log('handler called')
e.preventDefault()
}
export default function MyElement() {
return (
<div
onMouseDown={handler}
onTouchStart={handler}
>
Hello
</div>
)
}
It turn out it's not yet possible in React. One workaround is set a flag the first time touchStart it's received.
touchHandler = () => {
this.useTouch = true
this.realHandler()
}
mouseHandler = () => {
if (this.useTouch) return
this.realHandler()
}
With the caveat that the first touchStart can be lost in case of dragging.
Quite disappointing.

Disable taphold default event, cross device

I'm struggling to disable default taphold browser event. Nothing that I have found on Google provided any help. I have only Android 4.4.4 mobile and Chrome dev tools for testing. I tried CSS fixes, such as webkit-touch-callout and others, but apparently they don't work for Android, also they don't work in Chrome dev tools.
I also tried detecting right click, (e.button==2), it doesn't work.
I came up with a solution, but it solves one problem and creates another. I just want to have a custom action for 'long press' event for selected anchors and I don't want the default pop up to appear (open in a new tab, copy link address, etc.)
This is what I did:
var timer;
var tap;
$("body").on("touchstart", my_selector, function(e) {
e.preventDefault();
timer = setTimeout(function() {
alert('taphold!');
tap=false;
},500);
});
$("body").on("touchend", my_selector, function() {
if(tap) alert('tap');
else tap=true;
clearTimeout(timer);
});
It successfully disables the default taphold event and context menu doesn't appear. However it also disables useful events, such as swipe. The links are in a vertical menu and the menu is higher than the screen, so a user has to scroll it. If he tries to scroll, starting on an anchor, it won't scroll, it will alert 'tap!'
Any ideas how could I disable taphold default or how could I fix this code so it disables only tap events and leave default swipe events enabled?
Edit: Now I thought about setting a timeout, if the pointer is in the same place for lets say 100ms, then prevent default action. However e.preventDefault(); doesn't work inside setTimeout callback.
So now I'm just asking about the simplest example. Can I prevent default actions after certain amount of time has passed (while the touch is still there).
And this is my whole problem in a fiddle. http://jsfiddle.net/56Szw/593/
This is not my code, I got this from http://www.gianlucaguarini.com/blog/detecting-the-tap-event-on-a-mobile-touch-device-using-javascript/
Notice that while swiping the box up and down, scrolling doesn't work.
I got the solution. It was so simple! I had no idea there's an oncontextmenu event. This solves everything:
$("body").on("contextmenu", my_selector, function() { return false; });
For an <img> I had to use event.preventDefault() instead of return false.
document.querySelector('img').addEventListener('contextmenu', (event) => {
event.preventDefault();
}

Why is blur event not fired in iOS Safari Mobile (iPhone / iPad)?

I've two event handlers bound to an anchor tag: one for focus and blur.
The handlers fire on desktop, but in iphone and ipad only focus is fired correctly. Blur is not fired if I click outside the anchor tag (blur fires only when I click some other form elements in the page):
$("a").focus(function(){
console.log("focus fired");
});
$("a").blur(function(){
console.log("blur fired");
});
HTML:
<html>
<form>
test link
<div>
<input type="text" title="" size="38" value="" id="lname1" name="" class="text">
</div>
<div style="padding:100px">
<p>test content</p>
</div>
</form>
</html>
If an anchor has any events attached, the first tap on it in iOS causes the anchor to be put into the hover state, and focused. A tap away removes the hover state, but the link remains focused. This is by design. To properly control an application on iOS, you need to implement touch-based events and react to those instead of desktop ones.
There is a complete guide to using Javascript events in WebKit on iOS.
If you're working with touch devices you can use the touchleave or touchend event to handle when the user clicks outside the area.
$("a").on('touchleave touchcancel', function () {
// do something
});
For this to work you need to update your focus function to listen for an on click event as follows
$("a").on("click", function (e) {
if(e.handled !== true) {
e.handled = true
} else {
return false
}
// do something
})
I have check all the doc in the #NicholasShanks answer, but a little frustrated testing all the events.
Android and iOS:
Tested on Android Samsung S9
Tested on iOS iPad 5ºgen
Finally i have got a solution:
Seems iPad listen to mouseout as blur, and seems android listen perfectly to the blur event, i just add a ternary on this case to attach the right event (previously i have aimed to a mobile or tablet device instead of a computer.
// element >> element you want to trigger
// os >> function that return operative system 'ios' or 'android' in my case
element.addEventListener(os === 'ios' ? 'mouseout' : 'blur', () => {
// Do something
})
It's a hack, but you can get .blur to fire by registering a click handler on every DOM element. This removes focus from the previously focused element.
$('*').click();
$('html').css('-webkit-tap-highlight-color', 'rgba(0, 0, 0, 0)');
The second line removes the highlight when elements are clicked.
I know this is sub-optimal, but it may get you going.
The blur event does not fire because when you click outside the anchor tag on a non-clickable element, iOS ignores the click (and the click event does not fire).
There are a couple of threads regarding this (e.g. .click event not firing in Chrome on iOS). You can fix it by adding cursor: pointer to the <body> or some other element that the click will be performed on.
The simplest solution I've found is to just make document.body "clickable" at page initialization time:
document.body.onclick = function() {};
Then a click anywhere will blur the active element, just like on a desktop browser. Tested on iOS 15.3.1.

Categories