How to prevent Image map area click from propagating to link? - javascript

I have an HTML image map which has a few areas with links. I also have some Javascript functionality which, in certain cases, overrides the default functionality of the image map for some specific areas.
I have attached my function to the areas I want through this function (where el is the element, eventName is the name of the event and the eventHandler is the actual function):
function bindEvent(el, eventName, eventHandler)
{
if (el.addEventListener)
{
el.addEventListener(eventName, eventHandler, false);
}
else if (el.attachEvent)
{
el.attachEvent('on'+eventName, eventHandler);
}
}
So through my custom handler I am doing something like this:
function onAreaClick(e)
{
//my custom code here
e.cancelBubble = true;
if(e.stopPropagation)
e.stopPropagation();
return false;
}
//...
//assume looping through all areas of the imagemap here, with each element referred to by the variable area
bindEvent(area, 'click', onAreaClick);
The onAreaClick function in fact triggers OK, however I can't get the event to stop propagating. I tried cancelBubble, stopPropagation, and return false, but the link is still followed through. I also tried to change the phase from bubbling to capturing in the addEventListener() function call in bindEvent().
How can I stop this event from triggering the default action of the image map?

OK, so after some more experimentation I seem to got it working on all browsers without JS errors (or so it seems).
I created a function that stops the default handler, and I called it with the event as argument. This function looks like this:
function stopDefaultHandler(e)
{
if (e)
{
e.cancelBubble = true;
e.returnValue = false;
if (e.stopPropagation)
e.stopPropagation;
if (e.preventDefault)
e.preventDefault();
}
if (window.event && window.event.returnValue)
window.eventReturnValue = false;
}
It seems to work OK, but comments appreciated.

Did you try
e.preventDefault()

Related

How to prevent custom function execution when another function is executions

Here's my situation:
I have a custom menu on right mouse click for my project. Here, I have document.addEventListener on click, that makes this menu invisible, like this:
var i = document.getElementById("menu").style;
document.addEventListener('click', function(e) {
i.opacity = "0";
setTimeout(function() {
i.visibility = "hidden";
}, 100);
}, false);
And it's great, works well, but I'm implementing a dropdown submenu that should be opened when you click on a certain element, like so:
$('#change_color').click(function(){
if($('#back_color').hasClass('back_color')){
$('#back_color').removeClass('back_color')
}else{
$('#back_color').addClass('back_color')
}
})
The thing is that when I click on that #change_color then addEventListener is firing, which is obvious.
The question is – how can I prevent that listener function to execute when I click on #change_color?
You can prevent further propagation of the current event in the capturing and bubbling phases using event.stopPropagation() and for simplicity in your code use jQuery.toggleClass().
Code example:
$('#change_color').click(function (e) {
$('#back_color').toggleClass('back_color');
e.preventDefault();
e.stopPropagation();
});

How do you "bypass" mouse up?

I am trying to make it so that when a user clicks down, this happens.
In order,
Does something. (Not being specific, this isn't the important part.)
Mouse up is triggered.
Using: angular, html, css.
Not using: jQuery
Any suggestions?
Thanks!
You attach two event listeners, one while the user has the mouse pressed down mousedown. Once the user lets go the mouseup event is triggered. All mouse event listeners are passed an event object you can use to get information about the event ie: mouse x, and y positions.one of the methods available is event.preventDefault() this will stop the browser doing what it usually wants to do. Example: cmd/ctrl + s will cause the browser to save the html page. preventDefault will stop this.
document.addEventListener('mousedown' function (event) {
// Do something
})
document.addEventListener('mouseup', function (event) {
event.preventDefault()
})
To address OP comment:
var noMouseUp = true
document.addEventListener('mousedown', function () {
if (noMouseUp) {
// do something
noMouseUp = false
}
})
document.addEventListener('mouseup', function (event) {
if (!noMouseUp) {
noMouseUp = true
}
})
Use events.preventDefault(); in the mouseup callback.
Use, right after, event.stopPropagation(); to avoid the event passing to other layered elements.
bypassed_element.onclick = function(event){
event.preventDefault();
event.stopPropagation();
};

e.preventDefault() not bulletproof?

I have asked a similar question but didn’t get a real satisfying answer, so I will try again here. When I use code like this:
$("#element") .on( 'click', function() {
// do something
} )
.on( 'touchstart', function(e) {
e.preventDefault();
// do the same thing but on touch device like iPad f.e.
// and more over PLEASE do not fire the click event also!
} );
I am expecting that the click event is never never never fired (because of the hierarchy with which browser should work through the events) but in fact when I touch the element let’s say 20 times, than one time the click event fires also. Why?
And I also tried things like:
$("#element") .on( 'click', function() {
// do something
} )
.on( 'touchstart', function(e) {
e.preventDefault();
e.stopPropagation();
// do the same thing but on touch device like iPad f.e.
// and more over PLEASE do not fire the click event also!
return false;
} );
It seemed to be a little more solid but not bulletproof.
So I had to do:
$("#element") .on( 'click', function() {
if ( !touchdevice ) {
// do something
};
} )
.on( 'touchstart', function(e) {
e.preventDefault();
e.stopPropagation();
// do the same thing but on touch device like iPad f.e.
// and more over PLEASE do not fire the click event also!
return false;
} );
which seems to work but is awfully silly, isn’t it? Anyone with ideas what is this about? Thanks!
EDIT:
So I really had to do something like:
var touched;
$("#element") .on( 'click', function() {
if ( !touched ) {
// do something
};
} )
.on( 'touchstart', function(e) {
e.preventDefault(); // actual senseless here
e.stopPropagation(); // actual senseless here
touched = true;
// do the same thing but on touch device like iPad f.e.
// and more over PLEASE do not fire the click event also!
return false; // actual senseless here
} );
Come on guys! There must be a safe common way to use touchstart and click events on the same element ensuring that the click event is not fired (twice) to handle both touch sensible and regular browsers (or even the new combined ones). How would you do it?
I am expecting that the click event is never never never fired (because of the hierarchy with which browser should work through the events) [...]
You have wrong expectations of even.preventDefault().
event.preventDefault() prevents the default action that the browser performs for that element/event combination. E.g. submitting a form or following link. It does not prevent any other event handler from being executed.
e.stopPropagation() prevents the event from bubbling up so that event handlers added to ancestors are not executed.
However, you cannot use any of these methods to prevent the handler of a different event to be executed, so setting a flag seems indeed to be the right way to do this.
Right now I am using the following code in most places on my site which works very good and reliable:
var flag = false;
$("#element").on( 'touchstart click', function() {
if ( !flag ) {
flag = true;
setTimeout( function() {
flag = false;
}, 100 ); // someone else recommended 300 here but I use this value
// action here
};
return false;
} );
PS That is not my invention, but unfortunately I forgot the source because some time has passed.

Least amount of code to stop a link from firing (on all browsers)

When I want a function to stop a link and continue on executing my own code, I do this:
// IE
if (e.cancelBubble) {
e.cancelBubble = true;
}
// Firefox
if (e.stopPropagation) {
e.stopPropagation();
}
// Others
if (e.defaultPrevented) {
e.defaultPrevented();
}
alert('still executing my function');
Is all that really necessary, or could I do it with less code?
Simply make the function return false for javascript.
Since you mentioned in your comment you are using a jQuery click method, add the event.preventDefault().
$('#mylink').click(function(event) {
event.preventDefault();
//code here
})
jquery Source (thanks to BenjaminGreunbaum) for pointing out that jQuery normalizes events, thus event.returnValue is already handled.
For javascript, you'll want to add an eventListener.
function derp(event) {
event.preventDefault();
}
document.getElementById("mylink").addEventListener('click', derp, false);
You can use return false as it is effectively the same as calling both e.preventDefault and e.stopPropagation
e.preventDefault() will prevent the default event from occurring, e.stopPropagation() will prevent the event from bubbling up and return false will do both.
Write a simple return false; statement.
This will work in all browsers.

How to stop an event if not triggered directly?

Lets say there is a textbox and a button. On the click of button a function is executed, and on the focusout of textbox, the button is clicked. What I wanna know is, is there a way, I can determine that weather the user clicked the button, or it was triggered by focusout event of textbox, so that I may do some custom work in the click event, if it was triggered by focusout of textbox?
I could write some code, but I don't even have any idea where to begin with, I know the jQuery event and event.which property, but I wonder if it/they could be useful in this situation?
you can use event.target to determine which DOM element has initiated the event, then you can check if this is the button or the textbox.
check this out for more information: http://api.jquery.com/event.target/
from the documetation:
event.target
The target property can be the element that registered for the event
or a descendant of it. It is often useful to compare event.target to
this in order to determine if the event is being handled due to event
bubbling. This property is very useful in event delegation, when
events bubble.
This depends on how you're triggering the function from the textarea blur event, if you're simply triggering the click event using the following approach:
$('#btn').click(
function(e){
buttonActivation(e);
});
$('#txt').blur(
function(e){
$('#btn').click();
});
Then I'd suggest evaluating the originalEvent object to see what the original event was (if there was no originalEvent then the function was called by a programmatic click event, with jQuery; whereas if the originalEvent.type evaluates to click then the button must have been clicked.
function buttonActivation(e) {
if (!e) {
return false;
}
else {
var oEvent = e.originalEvent;
if (oEvent === undefined) {
console.log('Programmatic event');
}
else if (oEvent.type == 'click') {
console.log('User-initiated event');
}
}
}
JS Fiddle demo.
If, however, you're using something like the following (simply calling the same function from a different place):
$('#btn').click(
function(e){
buttonActivation(e);
});
$('#txt').blur(
function(e){
buttonActivation(e);
});
Then I'd recommend either directly assessing e.target or e.type:
function buttonActivation(e) {
if (!e) {
return false;
}
else {
var oEvent = e.type;
if (oEvent === 'blur') {
console.log('Programmatically-triggered event, on ' + oEvent);
}
else if (oEvent == 'click') {
console.log('User-initiated ' + oEvent + ' event');
}
}
}
JS Fiddle demo.
You can use the event.target. By default, jquery provides the event to the handler function.
Here's an example : jsfiddle
You can pass an additional parameters when triggering the event and check them in event handler.
So if you wrote
button$.trigger('click', 'hello');
then you can write the handler like
button$.on('click', function(e, someStr) {
console.log(someStr || 'Nothing passed');
// Obviously if someStr is undefined, the user clicked the button,
// otherwise the $.trigger() method has been called.
});

Categories