JS distinguish click and scroll on iPhone - javascript

I'm trying to close a Sidemenu onclick. however, touchstart also detects scrolling as a click, so is touchend.
how to just detect a click (not a scroll) on iPhone?
$('#html').on("click touchstart",function(e) {
var optionsmenue = $(".adminmenu_label");
if(!optionsmenue.is(e.target) && optionsmenue.has(e.target).length === 0) {
document.getElementById("Optionsmenu").style.width = "0%";
document.getElementById("Optionsmenu").style.transition = "0.2s ease-out";
document.getElementById("adblue").style.display = "block";
document.getElementById("whatever").style.display = "block";
document.getElementById("not_related").style.display = "block";
document.getElementById("still_not_related").style.display = "block";
document.getElementById("still_still_not_related").style.width = "100%";
}
});

Detecting for iOS and adding cursor:pointer works for me , IOS seems to have a problem with event delegation.
var iOS = ["iPad","iPhone","iPod"].indexOf(navigator.userAgent) > -1;
if(iOS) {
$('body').css({ cursor : 'pointer' });
}
$('#html').on("click",function(e) {
// No need for touch start click will do the trick;
});

should remove "touchstart" in
$('#html').on("click touchstart",function(e) {

Related

Remove Click Event only in a specific browser view

I have a Toggle displaying content. I am trying to remove its click event in larger than 600px of browser view. That means the Toggle click functionality should not work in larger view of 600px. Following is the code i used.
HTML:
<div class="trigger">Trigger</div>
<div class="content">This is the Toggle Displaying content</div>
let trigger = document.querySelector(".trigger");
let content = document.querySelector(".content");
mobilefunction=(el)=>{
let cs = window.getComputedStyle(el).display;
if(cs==="none") {el.style.display="block"}
else {el.style.display="none";}
}
responsivemenu=()=> {
let windowwidth = window.innerWidth;
if(windowwidth < 500) {
trigger.addEventListener("click", ()=>{mobilefunction(content)});
}
else {
trigger.removeEventListener("click", ()=>{mobilefunction(content)});
}
}
window.addEventListener("resize", responsivemenu );
responsivemenu();
I am trying to make Click event enable only in mobile and remove it for desktop. Seeking for experts help on this. Thanks in Advance!
I'd recommend to not add/remove the eventlistener but just check inside the listener callback.
By doing this you can drop all the resize handler stuff as the width is validated the second you click.
let trigger = document.querySelector(".trigger");
let content = document.querySelector(".content");
mobilefunction = () => {
if (window.innerWidth >= 500) {
return;
}
let cs = window.getComputedStyle(content).display;
if (cs === "none") {
content.style.display = "block"
} else {
content.style.display = "none";
}
}
trigger.addEventListener("click", mobilefunction);
<div class="trigger">Trigger</div>
<div class="content">This is the Toggle Displaying content</div>

disable vertical scrolling on touch device while using owl carousel

when dragging horizontal carousel left to right on touch device it also allows it to be dragged up and down which jiggles the whole page around. How can I disable vertical scrolling on owl carousel.
I can post the js file if anyone can help
Thanks in advance
Awesome css3 :)
.owl-carousel
{
-ms-touch-action: pan-y;
touch-action: pan-y;
}
This seems to work for me, at least on iOS, haven't tested on Android.
When you start sliding with mouse or touch I saw that Owl Carousel adds the class .owl-grab to the slider. I then found this code from #Turnerj and just put .owl-grab in the code.
Disable scrolling when touch moving certain element
It also works with multiple sliders on same page. Hope this helps! (I'm new to jQuery so there could probably be flaws to this solution)
window.blockMenuHeaderScroll = false;
$(window).on('touchstart', function(e) {
if ($(e.target).closest('.owl-grab').length == 1) {
blockMenuHeaderScroll = true;
}
});
$(window).on('touchend', function() {
blockMenuHeaderScroll = false;
});
$(window).on('touchmove', function(e) {
if (blockMenuHeaderScroll) {
e.preventDefault();
}
});
Use hammer.js with addEventListner for Classes.
I have tested with iOS (iphoneX) and Android (Nexus 5X) and work like a charme.
I hope can help!
window.blockMenuHeaderScroll = true;
var mc = new Hammer(document);
var classname = document.getElementsByClassName("elenco_image");
mc.on("swipeleft swiperight panleft panright", function(ev) {
console.log(ev.type + " gesture detected.");
window.blockMenuHeaderScroll = true;
});
mc.on("swipeup swipedown panup pandown", function(ev) {
console.log(ev.type + " gesture detected.");
window.blockMenuHeaderScroll = false;
});
for (var i = 0; i < classname.length; i++) {
classname[i].addEventListener('touchmove', function(evt) {
if (blockMenuHeaderScroll) {
evt.preventDefault();
}
}, {
passive: false
});
}
.owl-carousel
{
-ms-touch-action: pan-x;
touch-action: pan-x;
}
This worked for me as I need only horizontal scroll. Above code restricts the vertical scroll.
This will block vertical scrolling while dragging the image horizontally,
or prevent the horizontal pan while trying to v-scroll the page itself.
Important: Attach the event directly to the IMG element.
let blockScroll = false;
let blockPan = false;
$('.owl-carousel img').on('touchstart', '', ots);
$('.owl-carousel img').on('touchmove', '', otm);
let p0 = [0,0];
function ots(ev) { //save the first touch point
p0 = [ev.touches[0].screenX, ev.touches[0].screenY];
blockScroll = false;
blockPan = false;
}
function otm(event){
if(blockScroll)
event.preventDefault(); //don't let the window v-scroll
else if(blockPan)
{ //don't let OWL get the event and pan-x.
event.stopPropagation();
event.stopImmediatePropagation();
}
else
{ //calculate distance from the first touch point on every move
let t = event.touches[0];
let dx = t.screenX - p0[0];
let dy = t.screenY - p0[1];
if( Math.abs(dx) > Math.abs(dy) )
{
blockScroll = true;
event.preventDefault();
}
else
{
blockPan = true;
event.stopPropagation();
event.stopImmediatePropagation();
}
}
}
Tested on android (Chrome) and ios(Safari).
Some improvements on #Giovanni Locombi's answer to make the touch actions smoother. Works on iOS
Using Hammer.js from https://hammerjs.github.io/
window.blockMenuHeaderScroll = false;
var mc = new Hammer(document);
var classname = document.getElementsByClassName("owl-carousel");
mc.on("swipeleft swiperight panleft panright", function(ev) {
window.blockMenuHeaderScroll = true;
});
mc.on("panend swipeend", function (ev){
window.blockMenuHeaderScroll = false;
});
mc.on("swipeup swipedown panup pandown", function(ev) {
window.blockMenuHeaderScroll = false;
});
for (var i = 0; i < classname.length; i++) {
classname[i].addEventListener('touchmove', function(evt) {
if (blockMenuHeaderScroll) {
evt.preventDefault();
}
}, {
passive: false
});
}
None of the above worked for me.
but this worked.
.owl-carousel .owl-stage, .owl-carousel.owl-drag .owl-item{
-ms-touch-action: auto;
touch-action: auto;
}

jquery angularjs how to know if mouse down event is trigger by scrollbar of browser

I have a small panel which i close if mouse down button is pressed anywhere else than that panel, basically it clears the data to display and just with the help of angularjs ng-show i hide it if there is no data...application is in angularjs and jquery
please find the code below
var closeSearchResultsIfClickedOutside = function (e) {
if ($(e.target).parents('.searchResults').length === 0) {
var scope = angular.element($("#searchContainer")).scope();
scope.$apply(function () {
/*Cancels any existing search*/
if ($scope.defer != undefined) {
$scope.defer.resolve();
}
$scope.showSearchResults = false;
reinitialize();
});
$("html").off("mousedown", closeSearchResultsIfClickedOutside);
reinitializePanelsWidth();
}
};
but i dont want to close this panel if mouse down is on scrollbar of browser window or any scrollbar..please tell me how to do that
to fix the above problem i am not capturing both event, mouse down and click, if the target element on both event matches then only i am closing the panel.
/*
If mouse down and click on the same control, then only close the panel,
Click event closing is added to avoid closing panel on scrollbar click.
*/
var closeSearchResultsIfClickedOutside = function (e) {
if (e.type === 'mousedown') { /* only if mouse down is outside of search panel then only close the panel. */
if($(e.target).parents('.searchResults').length === 0)
{
isMouseDownOnSearchPanel = true;
}
else {
isMouseDownOnSearchPanel = false;
}
}
else if (e.type === 'click' && isMouseDownOnSearchPanel) { /*click event is implemented to avoid closing when mouse down is on scrollbar. you dont get click get event for scrollbar*/
var scope = angular.element($("#searchContainer")).scope();
$("html").off("mousedown", closeSearchResultsIfClickedOutside);
$("html").off("click", closeSearchResultsIfClickedOutside);
isMouseDownOnSearchPanel = false;
reinitializePanelsWidth();
}
};

jQuery on 'double click' event (dblclick for mobile)

I have the following jquery event handling function:
$('.target').on('dblclick', function() {
//respond to double click event
});
My issue is that this event handler doesn't work on touch devices (iPhone, iPad...). Can anyone recommend a reliable alternative to dblclick that works on touch devices and still allows comfortable double click use on full size devices?
I ended up building a custom double click function that will work on both mobile and desktop:
var touchtime = 0;
$(".target").on("click", function() {
if (touchtime == 0) {
// set first click
touchtime = new Date().getTime();
} else {
// compare first click to this click and see if they occurred within double click threshold
if (((new Date().getTime()) - touchtime) < 800) {
// double click occurred
alert("double clicked");
touchtime = 0;
} else {
// not a double click so set as a new first click
touchtime = new Date().getTime();
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="target">Double click me</div>
Alternatively, here is the JSfiddle Demo.
Add this to your index.html
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
I found the mobile zoom function would throw off Jquery's dblclick. Basically it says your viewport wont change effectively shutting off the zoom. This works for me on my Nexus 5 running Chrome.
I know the question has been answered but thought it would be worth putting the solution I use all the time, cheers:
var doubleClicked = false;
$('.target').on('click', function() {
if (doubleClicked) {
//do what you want to do on double click here
}
doubleClicked = true;
setTimeout(() => {
doubleClicked = false;
}, 300);
});
You can bind multiple event listeners on the element and use jQuery's tap event for the touch devices.
$( ".target" ).on({
dbclick: function() {
//do stuff
}, touch: function() {
//do the same stuff
}
});
Thanks for the solution - the only thing I did was add a timeout so that they could be treated as separate events
var touchtime = 0;
var delay = 800;
var action = null;
$(".target").on("click", function() {
/*Double Click */
if((new Date().getTime() - touchtime) < delay){
clearTimeout(action)
alert('dbl');
touchtime=0;
}
/* Single Click */
else{
touchtime = new Date().getTime();
action = setTimeout(function(){
alert('single');
},delay);
}
}));
Although I haven't tested it, might also be worth adding the following to a header section of any HTML <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/> as per: To "user-scalable=no" or not to "user-scalable=no"
The marked answer of #JRulle seems to work only for a single object, if u have many instances with the same class they will be considered as a single object
see the exampleFiddle example
My solution seems to work in cases like that
var touchtime = 0;
$('.target').on('click', function() {
if (touchtime == 0) {
touchtime = new Date().getTime();
} else {
if (((new Date().getTime()) - touchtime) < 800) {
alert("double clicked");
touchtime = 0;
} else {
touchtime = 0;
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<p class="target">click me!</p>
<p class="target">then click me!</p>
click link
Multiple targets with own doubleclick counter. The accepted solution has 2 bugs, that are fixed here:
If you click on target and click outside and click on target again within 800 ms, then the doubleclick event fires.
If you have multiple targets, click on different targets within 800 ms, and the doubleclick event fires.
$(document).on("click", function(e)
{
var MAX_DELAY_IN_MS = 800;
var current_time = new Date();
var targets = $(".target");
if ((typeof last_target == "undefined") ||
(last_target == 0))
{
last_target = e.target;
last_click = current_time;
}
else
{
if ((last_target == e.target) &&
((targets.is(e.target) == true) ||
(targets.has(e.target).length !== 0)) &&
(current_time - last_click < MAX_DELAY_IN_MS))
{
alert("double clicked");
}
last_target = 0;
last_click = 0;
}
});
div{display:inline-block; width:30px; height:30px; margin:5px;}
.target{background-color:lime;}
.no_target{background-color:orange;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="target"></div>
<div class="target"></div>
<div class="no_target"></div>
<div class="target"></div>
Programmatically all of the answers given above are fine.
When you double click on mouse button it's just the mass off your finger involved,
so it can be fast...
On the other hand when tapping touch screen usually much larger physical mass is involved.
Larger mass means slower times .
So my approach is "click two times" instead of double click.
Means a global variable e.g var ClickCounter=0;
Inside the function scope
ClickCounter++;
Check if ClickCounter ==2.
Execute your Code.
Reset counter ClickCounter=0
else return false or execute another code
I have an improvement to the code above, that didnĀ“t detect a doubleclick after a single click:
var touchtime = 0;
$(".target").on("click", function() {
if (((new Date().getTime()) - touchtime) < 500) {
alert("double clicked");
}
touchtime = new Date().getTime();
});
This code detects all doubleclicks. I also reduced the touchtime to 500ms (standard doubleclick-time).
The only way is to detect double touch yourselves. You can do it by persisting last touch event timestamp like below:
if (e.touches.length === 1) {
if (this.lastTouchEventTimeStamp) {
const timeInMillisecondsSinceLastTouch = e.timeStamp - this.lastTouchEventTimeStamp;
if (timeInMillisecondsSinceLastTouch > 80 && timeInMillisecondsSinceLastTouch < 400) {
// double tap will be detected here
this.lastTouchEventTimeStamp = undefined;
const dblClickEvent = new DragEvent('dblclick', {
view: window,
bubbles: true,
cancelable: true
});
e.target.dispatchEvent(dblClickEvent);
}
}
this.lastTouchEventTimeStamp = e.timeStamp;
}
Came across this thread and wanted to supply an updated answer.
function doubleClick(event, callback) {
var touchtime = $(event.target).data("touch-time");
if (touchtime == undefined || touchtime == 0) {
// set first click
$(event.target).data("touch-time", new Date().getTime());
} else {
// compare first click to this click and see if they occurred within double click threshold
if (((new Date().getTime()) - touchtime) < 800) {
// double click occurred
callback();
$(event.target).data("touch-time", 0);
} else {
// not a double click so set as a new first click
$(event.target).data("touch-time", new Date().getTime());
}
}
}
It can then be used as follows:
$(selector).click(function(event){
doubleClick(event, function(){
console.log("Hello World");
});
});
This uses the Data Attribute versus a global variable to get/set the Touch Time.
The standard dblclick should work in modern mobile browsers.
This is it... in CoffeeScript
onDblClick = -> "...your function to be fired..."
dbl_click = null
$(element).on 'mousedown', ->
onDblClick() if dbl_click
dbl_click = true
setTimeout () ->
dbl_click = false
, 250
You need to enter "return false" to the end of the function like below
var touchtime = 0;
$('.dbclickopen').click(function() {
if(touchtime == 0) {
//set first click
touchtime = new Date().getTime();
} else {
//compare first click to this click and see if they occurred within double click threshold
if(((new Date().getTime())-touchtime) < 800) {
//double click occurred
touchtime = 0;
window.location = this.href;
} else {
//not a double click so set as a new first click
touchtime = new Date().getTime();
}
}
return false;
});

Recommended way to enable touch events in Bootstrap 3?

Now that Bootstrap 3 is out, what is the recommended option for enabling touch? As before, there aren't many touch events in the bootstrap.js, though it is supposed to be a mobile first framework.
The last thing I've found on github suggests using fastclick.js, but that was before the v3.0 release.
My recommendation is to use Bootstrap alongside JQuery mobile, TouchSwipe, or Hammer.js . An example of a bootstrap touch carousel can be found here.
Start working on another fully working Touch Carousel on GitHub. This also includes drag events...
Despite I believe bootstrap is a joke of a css framework (especially due to no multileveled navigation), I would probably agree with others to go with some different carousel if you have a choice.
From my experience JQuery mobile will work rather smoothly but my site was not built alongside jquery mobile and the css belonging to it really messed the things up.
<script>
$(document).ready(function() {
$('.carouselresp').carousel({'data-interval': 6000, 'data-pause': "hover"});
var clicking = false;
var currentMousePos = 0;
var newMousePos = 0;
$('.carouselresp img').on('mousedown', function(event) {
clicking = true;
currentMousePos = event.pageX;
});
$('.carouselresp img').on('touchstart', function(event) {
clicking = true;
var touchstart = event.originalEvent.touches[0];
currentMousePos = touchstart.pageX;
});
$(document).on('mouseup', function(event) {
clicking = false;
});
$('.carouselresp img').on('touchend', function(event) {
clicking = false;
});
$(document).on('mousemove', function(event) {
if (!clicking) {
return;
}else {
if (event.pageX < currentMousePos) {
if ((currentMousePos - event.pageX) > 50) {
$('.carouselresp').carousel('next');
clicking = false;
}
} else {
if ((event.pageX - currentMousePos) > 50) {
$('.carouselresp').carousel('prev');
clicking = false;
}
}
}
});
$('.carouselresp img').on('touchmove', function(event) {
var touch = event.originalEvent.touches[0];
if (!clicking) {
return;
}else {
if (touch.pageX < currentMousePos) {
if ((currentMousePos - touch.pageX) > 50) {
$('.carouselresp').carousel('next');
clicking = false;
}
} else {
if ((touch.pageX - currentMousePos) > 50) {
$('.carouselresp').carousel('prev');
clicking = false;
}
}
}
event.preventDefault();
});
});
</script>
It works fine for me on android and iphone too, plus I am allowing the move event in browsers with no touch support.
I hope it helped.
TomHre

Categories