How to prevent touchend event after dragend? - javascript

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();

Related

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

In the mousedown event, is it possible to cancel the resulting click event? or pass info to it?

for arcane reasons I need to be able to cancel the click event via the mousedown event.
Briefly; I am creating a context menu in the mousedown event, however, when the user clicks on the page the context menu should disappear.
I am not able to use the mousedown event over the click in that scenario as I want the user to be able to click links inside the menu ( a full click would never travel to the <a> based menu elements ).
If it is any help, jQuery can be applied.
I would like to either be able to prevent the click event from happening from within the initial mousedown, or be able to pass information to the click event (via originalEvent or otherwise).
TIA
Seems to be impossible, neither FF nor Opera didnt cancel upcoming click when prevented in mousedown and/or mouseup (as side note: click is dispatched after mouseup if certain conditions met). testcase: http://jsfiddle.net/ksaeU/
I have just had the exact same problem. I fixed my context menu by closing it on mousedown and eating the mousedown event on the menu so that I can still receive clicks on the menu, like so:
$(document).one('mousedown.ct', null, function() { cmenu.hide(); return false; });
cmenu.bind('mousedown', function(e) { e.stopImmediatePropagation(); });
And in the hide() function I unbind the mousedown.ct again, in case it was closed due to a click on an item.
Hey, I think this is what you are trying to do with your code. If not, I apologize, I may have misunderstood the question. I used jQuery to get it done: http://jsfiddle.net/jackrugile/KArRD/
$('a').bind({
mousedown: function(){
// Do stuff
},
click: function(e){
e.preventDefault();
}
});

Intercepting all key presses with jQuery before they are processed

I have a web page and I need to intercept all keypresses before they get dispatched to whatever element in the dom has the focus. When the user types something like ~goto:/index.html: (which in fact will come from a barcode scanner) I need to capture the key presses after the ~ to parse them once I get to the second :. I've managed to get something with the $(document).keypress() as follows:
$(document).ready(function() {
$(document).keypress(function(e) {
// do the processing here and
// return false when ignoring keystrokes
});
});
The problem is that I get the keypress after it has gone to the focussed element. Anyway to get it before so that I can in fact reject it?
You will probably have better luck with keydown it should fire before the event
also do this
$(document).keydown(function(e) {
e.preventDefault();
});
calling preventDefault will stop normal process of the key press. Actually, you may be able to stay with keypress and just use the preventDefault to finish your interception needs.
read this about event bubbling.
http://www.quirksmode.org/js/events_order.html
this works for firefox:
document.addEventListener('keypress',function(e){alert('body1'); e.cancelBubble = true;},true)
I'm not sure what will work for i.e. as the document i linked to says in i.e. the event bubbles from inwards upwards. you may have to try a different way round this. e.g. you could add an event handler to all the element that you do not want them handling the event and then prevent them handling the event in that event handler.

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.

Multiple events firing from single action

I have an onclick event attached to a region in my page that causes a certain action to fire when the user clicks in it (naturally). I recently added an image to that region. When the user clicks on that image, I want another action to occur, and I do NOT want the action associated with the entire region to occur. However, I find that both events are, in fact fired when one clicks the image. How do I suppress the region-wide action when the image is clicked?
The issue you are running into is known as event bubbling. The click event of the image bubbles up to all parent elements of that node. You want to cancel bubbling.
The best way to do this that works across all browsers is by using a JavaScript framework. jQuery has a very simple way to do this. Other frameworks have similar mechanisms to cancel bubbling, I just happen to be most familiar with jQuery.
For example, you could do something like this in jQuery:
$('img').click(function () {
// Do some stuff
return false;// <- Cancels bubbling to parent elements.
});
Darit is correct, you need to stop the event from bubbling (propagating):
function imgEventHandler(e) {
// ^notice: pass 'e' (W3C event)
// W3C:
e.stopPropagation();
// IE:
if (window.event) {
window.event.cancelBubble = true;
}
}
In the event handler for the image do
event.cancelBubble = true;
and then at the end do
return false;

Categories

Resources