How to change all onClick events to TouchStart on iOS? - javascript

OnClick event has a timeout ~400ms before executing on iOS-browser (demo). And I want to change it to TouchStart event for all DOM-elements who have onClick. How can i make it?
I use jQuery and i tried check all elements for click function:
$('*').each(function() {
if($(this).click != null) {
// BUT all elements in DOM has click
}
})

I don't have an exact answer, but I think you should be able to make this do what you want.
For every element on your page that has an OnClick, add a class - say TouchTarget. Then use this in your startup function.
$('.TouchTarget').bind('touchstart', function (e) {
e.preventDefault();
touchStart(e, this);
});
Create a handler function that looks like this:
function touchStart(pEvent, pElement) {
//Do something with the touch.
}
If you only want to register if touch is available, then you can protect the bind call with
if (Modernizr.touch) {
}
I believe the reason for the delay in OnClick is because Safari is waiting to see if the touch is really a click or a drag, or some other gesture. This will recognize a simple touch quickly. I normally bind both touchstart and touchend when I need quick touches so that touchstart provides visual feedback and then touchend does something with the "click". This method does not have a delay built in.

Use a product like http://www.jqtouch.com/ or the code snipped provided here: http://cubiq.org/remove-onclick-delay-on-webkit-for-iphone.

Related

How to trigger code wrapped in one event with another onclick event

Have this code wrapped in HOVER Event...
$("#div_ID").hover(function() {
// perform stuff here...
}
);
I'd like to trigger the above when I click a link using the ONCLICK Event...
$("anchor_ID").click (function() {
$("div_ID").trigger('hover'); // Not sure if this is even correct
}
);
It's not working though. How can I accomplish this? Is it even possible?
Using JQuery only on FF v16, IE8, and GC v23
How about this:
var dosomething = function() {
// perform the stuff here
}
$('#div_ID').hover(dosomething);
$('anchor_ID').click(dosomething);
But if you are set on using .trigger, your problem might be that you forgot to include # before div_ID. And change hover to mouseenter (the "hover" function in jQuery is just a shortcut for "mouseenter" -- credit to #FabrícioMatté for catching that) That is:
//change this:
$('div_ID').trigger('hover');
//To this:
$('#div_ID').trigger('mouseenter');
Same might apply to anchor_ID, but I won't know unless you post your HTML.
Update: another suggestion from #FabrícioMatté: the this keyword inside of dosomething might be a bit confusing when you call it as shown above, so watch out for it. The this keyword will work differently than using .trigger, so it's just a heads up....
hover is not an event so you can't trigger it. .hover() is just a shorthand which attaches mouseenter and mouseleave handlers.
$("#anchor_ID").click(function() {
$("#div_ID").trigger('mouseenter');
});
Fiddle
Note that .hover when passed a single argument will attach the function to both mouseenter and mouseleave so you can trigger either of these.
I'd recommend attaching the handler with mouseenter instead of hover if you intend to execute the handler only when users move their mouse above the div.

Can mouseenter and click event exist together?

I am wondering if mouseenter and click event can exist together and they can both exist to TRUE when checked with:
if ((evt.type === 'mouseenter') && (evt.type === 'click'))
It is because when I mouse over the link, the mouseenter triggers (set to TRUE) and even when I clicked on it, the hover is still shown. Probably they could exist together but I'm no expert on this.
If someone can give insights, I would appreciate it a lot.
Also how can I trigger the click event during the mouseenter event?
The mouseenter event fires when the mouse enters the control. The click event fires when the mouse is clicked. They are two separate events which call two separate event handlers. If you click just as the mouse enters the element they will be called within a short timespan of one another but they are still two distinct events.
It is also important that you differentiate between the mouseenter and the mouseover events. mouseenter fires when the mouse physically enters an element, whereas mouseover fires continually while the mouse remains over an element.
While you cannot trigger the click event per se, you can call the same function that is called by the click event handler. For example if you have this:
var myfunc = function (e) { ... }
document.getElementById("id").onclick = myfunc;
Then you could simply call myfunc directly and you would get the same result as if the mouse was clicked.
They can 100% exist together, and this is a great question with no good answer... When you're on a mobile device, a mouseenter event will be thrown on tap... If you are also detecting onclick as well as mouseenter, then there will be a discrepancy between mobile devices and desktop machines.
It's kind of hard to solve such a small issue at the moment.
const x = document.getElementById('some_node')
x.onclick=(e)=>{
e.stopPropagation()
// this logic will be triggered on click for both desktop and mobile
}
x.onmouseenter=(e)=>{
e.stopPropagation()
// this logic will be triggered on click for mobile only (but will
//have already been triggered on desktop when cursor entered node)
}
The only workaround I came up for this, and I think it's pretty clever, is using a eventlistener for taps/touches. The order/priority that these events are fired goes: touch > mouseenter > click.
Since the touch event is fired first, you can add a touch event listener (which will only register on a mobile device), and change a variable that prevents the mouseenter event from being triggered (which is the logic that would generally be conflicting with the onclick logic)... like this:
let isMobile = false
x.addEventListener('touchstart',(e)=>{
isMobile = true
}, false);
Then your mouseenter would need to look like this:
x.onmouseenter=(e)=>{
e.stopPropagation()
if(!isMobile){
// this logic will no longer cause a conflict between desktop and mobile
}
}
they can exist on the same object, think a button with a hover state and then a click action. The click event, though will only read the click event since the enter event actually occurred earlier.
You can create a var like mouseIsOverand set it to true when the enter event fires. I can be safely assumed, though that if a click happens the mouse is over the same target.
The two events may happen at the same time, but they will still be processed on after the other. So the if you posted will never evaluate to true.
If you look at your code again you can see that it doesn't make sense. How can something be X and Y at the same time? It can't.
for the first question i think u got an answer....
however, for Also how can I trigger the click event during the mouseenter event?
u can use trigger() function..
http://jsfiddle.net/PDhBW/2/
if u want to read more about trigger
here is the link
http://api.jquery.com/trigger/
With Jquery event delegation, You can use binding multiple events at once
$('#IdElement').on('mouseenter click', function () {
//Your Code
});
http://jqfundamentals.com/chapter/events

How to prevent touchend event after dragend?

I'm working on a mobile site and struggling with events firing when I don't want them to.
For the sake of simplicity, it's written something like this (in jQuery):
el.on('touchend', function(ev) {
ev.preventDefault();
// fire an ajax call
};
However, sometimes a user would hit the item when scrolling the page, causing the ajax request to fire (thus changing the page state).
I couldn't think of a way around it (ev.stopPropagation() didn't work) , so I decided watch for dragstart and dragend events.
el.on('dragstart', function() {
el.off('touchend');
});
el.on('dragend', function(ev) {
ev.stopPropagation(); // <-- seems to do nothing
// add back the event above (the function is set to a var)
});
If I alert inside the touchend callback, I get confirmation that the touchend event did in fact fire after I stopped dragging.
Does anyone have any idea how to prevent any other events from firing? I'm hoping I'm just being blind and missing something obvious.
You can't stop an event from firing, you can only prevent the default behavior for that event from happening.
If you're worried about the state of your page changing before the touchend event fires, you should just change your function to check for and then account for the state change.
I think in a case like this you should use event.stopImmediatePropagation();

What's the cross-browser way to capture all single clicks on a button?

What's the best way to execute a function exactly once every time a button is clicked, regardless of click speed and browser?
Simply binding a "click" handler works perfectly in all browsers except IE.
In IE, when the user clicks too fast, only "dblclick" fires, so the "click" handler is never executed. Other browsers trigger both events so it's not a problem for them.
The obvious solution/hack (to me at least) is to attach a dblclick handler in IE that triggers my click handler twice. Another idea is to track clicks myself with mousedown/mouseup, which seems pretty primitive and probably belongs in a framework rather than my application.
So, what's the best/usual/right way of handling this? (pure Javascript or jQuery preferred)
Depending on your situation you can use different approaches, but I would suggest using namespaced event handlers with jQuery like this:
function eventHandler(event) {
// your handler code here
doSomeMagic();
}
var element = $('#element');
element.one('click.someNameSpace', function(event){
// first we unbind all other event handlers with this namespace
element.unbind('.someNameSpace');
// then we execute our eventHandler
eventHandler();
}).one('dblclick.someNameSpace', function(event){
// If this fires first, we also unbind all event handlers
element.unbind('.someNameSpace');
// and then execute our eventHandler
eventHandler();
});
I'm not sure this will work the way you want it, but it's a start, I guess.
Mousedown and mouseup works just like the click functions, unfortunately so much that when IE omits a click because of a doubleclick it will also omit the mousedown and mouseup. In any case, you can add both click and dblclick to the same object and feed the clicks through a function that sort out any click happening too close to the last.
<div onclick="clk()" ondblclick="clk()"></div>
lastclicktime=0
function clk(){
var time=new Date().getTime()
if(time>lastclicktime+50){
lastclicktime=time
//Handle click
}
}
I by the way just found out that, at least in Firefox the dblclick event is not given an event time, therefore I had to resolve to the Date method.

jQuery live('click') firing for right-click

I've noticed a strange behaviour of the live() function in jQuery:
normal
live
$('#normal').click(clickHandler);
$('#live').live('click', clickHandler);
function clickHandler() {
alert("Clicked");
return false;
}
That's fine and dandy until you right-click on the "live" link and it fires the handler, and then doesn't show the context menu. The event handler doesn't fire at all (as expected) on the "normal" link.
I've been able to work around it by changing the handler to this:
function clickHandler(e) {
if (e.button != 0) return true;
// normal handler code here
return false;
}
But that's really annoying to have to add that to all the event handlers. Is there any better way to have the event handlers only fire like regular click handlers?
It's a known issue:
It seems like Firefox does not fire a
click event for the element on a
right-click, although it fires a
mousedown and mouseup. However, it
does fire a click event on document! Since .live catches
events at the document level, it sees
the click event for the element even
though the element itself does not. If
you use an event like mouseup, both
the p element and the document
will see the event.
Your workaround is the best you can do for now. It appears to only affect Firefox (I believe it's actually a bug in Firefox, not jQuery per se).
See also this question asked yesterday.
I've found a solution - "fix" the the live() code itself.
In the unminified source of jQuery 1.3.2 around line 2989 there is a function called liveHandler(). Modify the code to add one line:
2989: function liveHandler(event) {
2990: if (event.type == 'click' && event.button != 0) return true;
This will stop the click events from firing on anything but the left-mouse button. If you particularly wanted, you could quite easy modify the code to allow for "rightclick" events too, but this works for me so it's staying at that.
You can actually rewrite it as:
function reattachEvents(){
$(element).unbind('click').click(function(){
//do something
});
}
and call it when you add a new dom element, it should have the expected result (no firing on the right click event).
This is an unfortunate consequence of how live is implemented. It's actually uses event bubbling so you're not binding to the anchor element's click event, you're binding to the document's click event.
I solved this by using mousedown events. In my situation the distinction between mousedown and click didn't matter.

Categories

Resources