Firefox DOM2 mouse down event selects elements when using stopPropagation - javascript

I have a link element where I capture the mousedown event and stop the event from bubbling so that other elements in the page don't get selected. However in firefox (3 & 3.5) when i use the DOM 2 event model It still selects other elements in the page.
I have tested it in opera and it works fine without selecting other elements. Also another weird issue is that if I use the DOM 0 event model it works fine and doesn't select other elements. Is this a bug in firefox or am I just doing it wrong?
Here are the 2 event handlers I used to test
past.addEventListener('mousedown', function (e) {
e.stopPropagation();
return false;
}, false);
past.onmousedown = function (e) {
e.stopPropagation();
return false;
};

Have you tried e.preventDefault()? stopPropagation will stop the event handlers on ancestor elements being invoked, but this is not the same thing as preventing the default action from being taken. As the DOM specs don't really specify how mouse events and selection should interact in terms of the event model, it may be one of those areas where one browser does it one way, one does it another, and neither is "right" or "wrong".

Related

Direct vs delegation and bubbling vs capturing in jQuery

HTML
<div>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
jQuery
$('div span').on('click', function(){
//direct - 1st method
});
$('div').on('click','span', function(){
//delegation - 2nd method
});
I have used both above method in my code. I know second method is better due to it has only got single handler. My problems are:
Is first method (direct) refers to the concept called event capturing? Is it an example for event capturing?
Is second method (delegation) refers to the concept called event bubbling? Is it an example for event bubbling?
It appears as though All jQuery event methods use Event Bubbling, not Event Capturing.
Therefore, both of your examples will use Event Bubbling.
There is an edge case with focus and blur events not bubbling in some browsers. In the affected browsers, Event Capturing is used for focus and blur events.
For reference, you can simply view the source. http://code.jquery.com/jquery.js
$('div span').on('click', function(){
//direct - 1st method
});
This event only attached the event handler to the spans inside Div that are currently present in the DOM.. i.e; if a new span element is added to the div , that span will not have a click event associated with it..
The first and second one are example's of Event Bubbling
There comes the concept of Event delegation where in the ancestor is given the event handler and it is delegated to the children..
The second example is an example of event delegation .
Wherein event is attached to the parent element..So all the span element's inside the div class are attached to the event handler ..
So if a new span element is added to the div , becoz the event is associated with the span's ancestor the event will fire in this case
This helps in cases
$('div').on('click','span', function(){
//delegation - 2nd method
});
I have no idea where event capturing is used in the jQuery library
Answers to your questions:
This isn't bubbling, capturing, or delegating. It's just adding an event listener directly to an element.
Yep, this is delegation that under the hood relies on clicks bubbling up.
Event bubbling and capturing are different implementations of the same concept, brought to you by Microsoft and Netscape, respectively. Both listening for events on parent elements. Note that they occur in a different order: capturing happens from the parent down to descendent, whereas bubbling happens the other way around.
More details and its history on PPK's website: http://www.quirksmode.org/js/events_order.html
Modern browsers support both capture and bubbling (bubbling is the default now), and you can specify which one you want to use when you use the native addEventListener:
element.addEventListener('click', function(){}, false); // bubble
element.addEventListener('click', function(){}, true); // capture
However, some events, such as focus, blur, scroll, mouseover, etc only are supported through capture phase events, so you MUST specify "true" when you use addEventListener.
Unfortunately, it looks like jQuery doesn't support delegation for all capture phase events, only focus and blur (see https://github.com/jquery/jquery/blob/ad032d3c7df04827989a4187117614c29bf3a4ad/src/event.js#L728).
The short answer: for delegation of capture-phase events other than focus and blur, you need to use the native addEventListener, not jQuery.

How attach document.click event without touching some element?

I need to click on a document to call some function, but the problem is that when I click on some element that want it doesnt react, so the code:
<body>
<div class="some_element">
some element
</div>
</body>
and js:
$(document).click(function(){
//something to happen
})
and now if I click on the div with class="some_element" the document.click event will be called, but I need to call that event ONLY when I click on the document; or it is possible the make this element an exception?
More detailed:
$('#forma').click(function(e){
e.stopPropagation();
$('#assignment_type_list').slideUp();
})
Lets say #forma - its a parent element of those element, so when I click on the page I want to slideUp someElement and:
$('#assignment_type_select, #assignment_type_label').click(function(){
$('#assignment_type_list').slideToggle();
})
this is the elements when they are clicked the other element is toggled, but the problem is that when I click on this elements the $('#forma').click - also executes, because its parent and the e.stopPropagation() - doesn't help.
All this stopPropagation stuff is right, though this'll cause your script to throw errors on older versions of a certain browser. Guess which one? a cross-browser way:
$('#elem').click(function(e)
{
e = e || window.event;//IE doesn't pass the event object as standard to the handler
//event would normally work, but if you declared some event variable in the current scope
//all falls to pieces, so this e || window.event; thing is to be preferred (IMO)
if (e.stopPropagation)//check if method exists
{
e.stopPropagation();
return;
}
e.cancelBubble = true;//for IE
});
However, you wanted to check if the element that was actually clicked, is the one you need. The problem with that is, that the way the event is passed through the DOM. In W3C browsers the event is first passed to the document, and then clambers down to the element that was actually clicked (propagates through the dom). By contrast IE dispatches its events on the element itself, and then sends it up to the document (except for the change event triggered by select elements... to add insult to injury). What this effectively means is that a click event that is registered in to body element in W3C browsers might be on its way to a checkbox of sorts, or it could be a click inside an empty div. Again, in IE, when a click event reaches the body tag, it could have been dispatched too any element on the page. So it may prove useful in your case to google: event delegation, or turn to jQuery's .delegate() method.
Or check the event object to see if the event is allowed to propagate through or not:
var target = e.target || e.srcElement;//target now holds a reference to the clicked element
The property names neatly show the difference between the bubbling model and the propagating one: in the first case (srcElement), the event is coming from a source element in the dom. In the W3C propagating model, the event is cought while it's headed for a target element somewhere in the dom. Look at it like a heat-seeking missile (w3c) versus a shower of debris after the target was shot down (IE, always the destructive one, and in this case often to late to respond to the events, and therefore to late to handle them:P)
One way to do it is to check for the event's target.
$('html').click(function(event){
if (event.target != this){
}else{
//do stuff
}
});
Here's a working fiddle
Elements on the document are part of the document, so if you click "some_element" in the document, it is obvious that event registered on document will be fired/triggered. If you dont want to execute code which was for "document" then first get the element OR "event source" which originates this event, and check if it was "some_element" in your question above.

Blur event stops click event from working?

It appears that the Blur event stops the click event handler from working? I have a combo box where the options only appear when the text field has focus. Choosing an option link should cause an event to occur.
I have a fiddle example here: http://jsfiddle.net/uXq5p/6/
To reproduce:
Select the text box
Links appear
Click a link
The blur even occurs and the links disappear
Nothing else happens.
Expected behavior:
On step 5, after blur occurs, the click even should also then fire. How do I make that happen?
UPDATE:
After playing with this for a while, it seems that someone has gone to great lengths to prevent an already-occurred click event from being handled if a blur event makes the clicked element Un-clickable.
For example:
$('#ShippingGroupListWrapper').css('left','-20px');
works just fine, but
$('#ShippingGroupListWrapper').css('left','-2000px');
prevents the click event.
This appears to be a bug in Firefox, since making an element un-clickable should prevent future clicks, but not cancel ones that have already occurred when it could be clicked.
Other things that prevent the click event from processing:
$('#ShippingGroupListWrapper').css('z-index','-20');
$('#ShippingGroupListWrapper').css('display','none');
$('#ShippingGroupListWrapper').css('visibility','hidden');
$('#ShippingGroupListWrapper').css('opacity','.5');
I've found a few other questions on this site that are having similar problems. There seem to be two solutions floating around:
Use a delay. This is bad because it creates a race condition between the hiding and the click event handler. Its also sloppy.
Use the mousedown event. But this isn't a great solution either since click is the correct event for a link. The behavior of mousedown is counter-intuitive from a UX perspective, particularly since you can't cancel the click by moving the mouse off the element before releasing the button.
I can think of a few more.
3.Use mouseover and mouseout on the link to enable/disable the blur event for the field. This doesn't work with keyboard tabing since the mouse is not involved.
4.The best solution would be something like:
$('#ShippingGroup').blur(function()
{
if($(document.activeElement) == $('.ShippingGroupLinkList'))
return; // The element that now has focus is a link, do nothing
$('#ShippingGroupListWrapper').css('display','none'); // hide it.
}
Unfortunately, $(document.activeElement) seems to always return the body element, not the one that was clicked. But maybe if there was a reliable way to know either 1. which element now has focus or two, which element caused the blur (not which element is blurring) from within the blur handler. Also, is there any other event (besides mousedown) that fires before blur?
click event triggers after the blur so the link gets hidden. Instead of click use mousedown it will work.
$('.ShippingGroupLinkList').live("mousedown", function(e) {
alert('You wont see me if your cursor was in the text box');
});
Other alternative is to have some delay before you hide the links on blur event. Its upto you which approach to go for.
Demo
You could try the mousedown event instead of click.
$('.ShippingGroupLinkList').live("mousedown", function(e) {
alert('You wont see me if your cursor was in the text box');
});
This is clearly not the best solution as a mousedown event is not achieved the same way for the user than a click event. Unfortunately, the blur event will cancel out mouseup events as well.
Performing an action that should happen on a click on a mousedown is bad UX. Instead, what's a click effectively made up of? A mousedown and a mouseup.
Therefore, stop the propagation of the mousedown event in the mousedown handler, and perform the action in the mouseup handler.
An example in ReactJS:
<a onMouseDown={e => e.preventDefault()}
onMouseUp={() => alert("CLICK")}>
Click me!
</a>
4.The best solution would be something like:
$('#ShippingGroup').blur(function()
{
if($(document.activeElement) == $('.ShippingGroupLinkList'))
return; // The element that now has focus is a link, do nothing
$('#ShippingGroupListWrapper').css('display','none'); // hide it.
}
Unfortunately, $(document.activeElement) seems to always return the
body element, not the one that was clicked. But maybe if there was a
reliable way to know either 1. which element now has focus or two,
which element caused the blur (not which element is blurring) from
within the blur handler.
What you may be looking for is e.relatedTarget. So when clicking the link, e.relatedTarget should get populated with the link element, so in your blur handler, you can choose not to hide the container if the element clicked is within the container (or compare it directly with the link):
$('#ShippingGroup').blur(function(e)
{
if(!e.relatedTarget || !e.currentTarget.contains(e.relatedTarget)) {
// Alt: (!e.relatedTarget || $(e.relatedTarget) == $('.ShippingGroupLinkList'))
$('#ShippingGroupListWrapper').css('display','none'); // hide it.
}
}
(relatedTarget may not be supported in older browsers for blur events, but it appears to work in latest Chrome, Firefox, and Safari)
If this.menuTarget.classList.add("hidden") is the blur behavior that hides the clickable menu, then I succeeded by waiting 100ms before invoking it.
setTimeout(() => {
this.menuTarget.classList.add()
}, 100)
This allowed the click event to be processed upon the menuTarget DOM before it was hidden.
I know this is a later reply, but I had this same issue, and a lot of these solutions didn't really work in my scenario. mousedown is not functional with forms, it can cause the enter key functionality to change on the submit button. Instead, you can set a variable _mouseclick true in the mousedown, check it in the blur, and preventDefault() if it's true. Then, in the mouseup set the variable false. I did not see issues with this, unless someone can think of any.
I have faced a similar issue while using jQuery blur, click handlers where I had an input name field and a Save button. Used blur event to populate name into a title placeholder. But when we click save immediately after typing the name, only the blur event gets fired and the save btn click event is disregarded.
The hack I used was to tap into the event object we get from blur event and check for event.relatedTarget.
PFB the code that worked for me:
$("#inputName").blur(function (event) {
title = event.target.value;
//since blur stops an immediate click event from firing - Firing click event here
if (event.relatedTarget ? event.relatedTarget.id == "btnSave" : false) {
saveBtn();
}
});
$("#btnSave").click(SaveBtn)
As already discussed in this thread - this is due to blur event blocking click event when fired simultaneously. So I have a click event registered for Save Btn calling a function which is also called when blur event's related Target is the Save button to compensate for the click event not firing.
Note: Didnt notice this issue while using native onclick and onblur handlers - tested in html.

jquery - perform effect on any event

i have 5 elements in a page.
i have selected them using class names $('.class')
i am trying to perform a function for those selected elements irrespective of event (click or hover or watever).
eg:
$('.class').hover(function(){definition1});
$('.class').click(function(){definition1});
i dont want to have 2 seperate event as above 2, instead i want the function to be executed irrespective of whether its hover or click event.
$('.class').bind('click mouseenter', function() {
// Go nuts.
});
(if using jQuery >= 1.7, swap bind() with on().)
Keep in mind that hover()'s second argument is for mouseleave event, which you haven't written anything for here.
If you want to cover most events, pass in 'blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error' as the first argument.
You could also try to detect them with code by iterating over properties that start with on, but it sounds too flaky to me.
To bind multiple events to one element in jQuery 1.7 and later you can do the following by separating event names by spaces:
jQuery('.class').on('click hover mousenter mouseleave', function(event){
// do what you need to do
});
which you can see in jsfiddle.
But: be careful, because you can easily fire the event too much times (more than necessary and more than enough). By binding so many events some may be called unnecessarily (as in the example above the code will be fired twice when the mouse cursor will leave the element it hovered over).
If you do not want to exec a function without any event put it in
$(function(){
function test(){definition1}
});
then in html
<body onload="test();">

How to call JS to click a table element

Assume I get a table element with ID="emTab", how do I call JS to click it?
Thanks.
document.getElementById("emTab").onclick = function() {
// your code goes here
};
See element.onclick
To trigger click event
document.getElementById("emTab").click();
See element.click
The click method is intended to be
used with INPUT elements of type
button, checkbox, radio, reset or
submit. Gecko does not implement the
click method on other elements that
might be expected to respond to
mouse–clicks such as links (A
elements), nor will it necessarily
fire the click event of other
elements.
Non–Gecko DOMs may behave differently.
When a click is used with elements
that support it (e.g. one of the INPUT
types listed above), it also fires the
element's click event which will
bubble up to elements higher up the
document tree (or event chain) and
fire their click events too. However,
bubbling of a click event will not
cause an A element to initiate
navigation as if a real mouse-click
had been received.
Cross browser way
If you can use jQuery then it would be
$("#emTab").trigger("click");
Firing events cross-browser - http://jehiah.cz/archive/firing-javascript-events-properly
its simple using JQuery
$('#emTab').click(functionToCall);
while in JS
document.getElementById('emTab').onclick = function() {};
for details on DOM events:
http://www.howtocreate.co.uk/tutorials/javascript/domevents

Categories