I have following html on my page:
<div class="group-one" >
<p><span id="handle" draggable="true">::</span> click me</p>
</div>
<div class="group-two" draggable="true">
<p>I should be dragged</p>
</div>
Now what I want is that when #handle is dragged, the drag event should be delegated to div.group-two and element under move cursor should be div.group-two either. This is what I have tried:
$('#handle').mousedown(function(e){
$('.group-two').trigger(e);
});
$('#handle').on('dragstart', function(e){
$('.group-two').trigger(e);
});
$('.group-two').on('dragstart', function(e){
console.log('dragestart triggered on group-two');
});
$('.group-two').mousedown(function(e){
console.log("mousedown triggered on group-two");
});
Here is a jsfiddle.
The problem here is that although event is delegated to div.group-two but element being dragged under the move cursor is still span#handle.
Now my question is that, Is it possible to delegate drag in this manner? If it is, then any hint how to achieve it.
Note that I am using plain jQuery not jQuery UI.
Probably not. Personally it doesn't work for me, and after a bit of digging I found this extension someone made to help resolve it: https://www.bitovi.com/blog/delegate-able-drag-drop-events-for-jquery
I suspect it has something to do with the originalEvent being a trusted event and hence we can't modify its contents.
If you don't want to use the extension, perhaps consider relying on the quirk that users can only drag one thing at a time; and hence storing the data in a global variable (if its just going to be in the browser) would work. That's what I'm about to do :)
Related
while testing my JavaScript I have the following problem:
$('#idOfMyElement').click();
is executed. But I want to verfiy with my test, that is is not executed, because it has the following CSS:
<span style="cursor: not-allowed; pointer-events: none;" id="idOfMyElement"></span>
I debugged it and it is sure, that when the .click() is executed, it has DEFINITELY the mentioned CSS-attributes. In my normal program it works (means that the click doesn´t work), but in my test the click works, even if it shouldn´t.
I have no clou, what might be the problem.
Thanks for your help!
Looks like in your test you are triggering the event programmatically by using $('#idOfMyElement').click();; in that case it is not bound by the CSS mouse rules, and thus the click handlers will get executed.
You need to check the mouse pointer rules before triggering the click event in your test suite.
Prevent the default click event using jQuery:
$('#idOfMyElement').on('click', function(e) {
e.preventDefault(); });
* UPDATE *
Now that I know what you're trying to do, I highly recommend using javascript over CSS for this because CSS does not work the way you're trying to use it – Javascript does. Instead of using CSS attributes, use Javascript variables.
When you want the element to be clickable,
$('#idOfMyElement').prop('disabled', false);
When it should be unclickable,
$('#idOfMyElement').prop('disabled', true);
The browser takes care of the cursor without needing CSS, and click events should react appropriately. Hope that was helpful!
Pointer events only respond correctly to a real pointer event. If you trigger click() function it fires in all times that you make it. Just add a condition reading if pointer events is active or replace it by a disabled attribute
Is there a way to give precedence to an event? So in the below example it always fires the div1 event first but I want to fire the div2 event first. I could move div2 outside of the div1 div but it would include a bit more work because of other things (which I will do if it's the best option).
Also, is this a modern method? I know people talk about using .on over .live, but I don't think .click has a problem does it?
<div id="div1">
Various content etc.
<div id="div2">XXclickable content hereXX</div>
</div>
$('#div1').click(function(e) {
alert("clicked 1");
});
$('#div2').click(function(e) {
alert("clicked 2");
});
I tried this on JSFiddle, with every version on jQuery available, on both Firefox and Chrome and the div2 event in your example code always fired first. And from my understanding of even propagation/bubbling, this would have always been the case.
jsfiddle
Event delegation would probably be a better idea regardless. That is to say, not attaching an event handler directly to div2 in the first place, but adding additional logic to the div1 handler and checking the event.target for identity of the caller.
jsfiddle
I am adding events to links that are loaded via ajax. Here is a simplified example of the html:
<div class="ajax-content">
<div class="parent">
Click here
</div>
</div>
All content within ".ajax-content" is loaded via ajax. I don't want the click event for ".event-link" to bubble up to ".parent". If it was not loaded via ajax I could do this:
$$('.event-link').addEvent('click', function(event){
event.stopPropagation();
event.preventDefault();
//do stuff
});
However, I can't figure out how to accomplish the same behavior with (click:relay). This is what I am trying:
$$('.ajax-content').addEvent('click:relay(.event-link)', function(event){
event.stopPropagation();
event.preventDefault();
//do stuff
});
How do I prevent the click event from firing on '.parent'? (I also tried other syntax - event.stop() and returning false, but they had the same results.)
consider your DOM order and order of event propagation from the top of the DOM tree down:
<div class="ajax-content">
<div class="parent">
Click here
</div>
</div>
you attach the event to div.ajax-content (the delegator). which means, by the time that it hits it, it ALREADY needs to have bubbled through a.event-link, then div.parent and then finally down to div.ajax-content. there is no point in stopping it then, div.parent will come first anyway:
http://jsfiddle.net/dimitar/ChrCq/
here's what happens when you stop the event from the .parent before it reaches the delegator:
http://jsfiddle.net/dimitar/ChrCq/1/
delegation is not w/o it's downsides, i am afraid :)
you may want to also read this recent question / answer that went into some more caveats of delegated events and how they differ from normal events, how to work around the difficulties by alternating delegators. Make (possibly dynamically loaded) element clickable via JavaScript, but give precedence to links contained within - I am still hoping the event delegation in mootools may change somewhat but I just don't see how it will help things in your case.
I was trying to prevent a delegated click event from firing on div.parent. This can be accomplished in my particular situation by adding a check on the event target in the div.parent event:
$$('.ajax-content').addEvent('click:relay(.event-link)', function(event){
console.log("hi");
event.preventDefault();
//do stuff
});
$$('.ajax-content').addEvent('click:relay(.parent)', function(event) {
if (event.target.match('a')) return false;
console.log("parent");
});
Thanks to Dimitar for pointing me in the right direction!
I have HTML similar to the following in my page
<div id="someDiv">
<img src="foo.gif" class="someImg" />
</div>
The wrapper div is set up such that when it is clicked, it's background-color changes using the following jQuery code.
$("div").click(function(event){
$(this).css("background-color", "blue");
});
I also have some jQuery associated with my img that will do some other function (for the sake of argument I am going to display and alert box) like so:
$("img[class=someImg]").click(function(event){
alert("Image clicked");
});
The issue I have come across is that when I click on the img, the event associated with the div is also triggered. I'm pretty sure that this is due to the way that jQuery (or indeed JavaScript) is handling the two DOM elements - clicking the img would require you to also technically click the div, thus triggering both events.
Two questions then really:
Is my understanding of the
DOM/JavaScript flawed in some way or
is this actually how things are
occurring?
Are there any jQuery methods that
would allow me to perform actions on
a child element without invoking
those associated with its parent?
That is known as event bubbling, you can prevent it with stopPropagation():
$("img[class=someImg]").click(function(event){
alert("Image clicked");
event.stopPropagation();
});
.
Is my understanding of the DOM/JavaScript flawed in some way or
is this actually how things are
occurring?
That is because of what is known event bubbling.
Are there any jQuery methods that would allow me to perform actions
on a child element without invoking
those associated with its parent?
Yes, you need stopPropagation()
No, this is by design. Events bubble up through the entire dom, if you put another handler on body, it would fire too
Yes :) JQuery normalizes the event object, so adding event.stopPropagation() in your img click handler will give you the behavior you expect on all browsers
The problem you just facing is called "event bubbling". That means, if you click on a nested
element, that click event will "bubble up" the DOM tree.
If other elements also are bound to an click event, their listeners will fire aswell.
Solution to prevent this is called:
stopPropagation()
which is used within your event handler
$("img[class=someImg]").click(function(event){
event.stopPropagation();
alert("Image clicked");
});
This is what's called event bubbling, and you can stop it to get the behavior you want with .stopPropagation() (or return false; if you want to stop the event completely, including handlers on the same level), like this:
$("img[class=someImg]").click(function(event){
alert("Image clicked");
event.stopPropagation();
});
You can view a demo here, comment it out and click run again to see the difference.
The short version is that when most event types happen, they happen on the immediate element, then bubble up the DOM, occurring on each parent as they go. This is not jQuery specific at all, native JavaScript does this. If you're more curious, I'd read the linked article, it has a great explanation of what's going on.
Refer to this link (open firebug). I have a "dropdown" html element which has an event observer looking for mouseover. It's working, but it continuously fires mouseover events while you are mousing over the other elements inside it. I am guessing this is because of bubbling.
Is there a way to only make it fire the event on the initial mouseover? I want it to do an Effect and this is breaking the effect. I am sure it's just something basic I am not doing.
Thanks for the help.
Figured it out. With the latest version of prototype you can create onmouseenter and onmouseleave events, which only fire once. Thanks to the Protoype Google group.
I believe that you may want to use Event.stop(event)
Documentation: Prototype: Event.stop
You should only be observing the mouseover event on elements with the dropdown_label class.
Given your HTML:
<div class="dropdown" id="">
<div class="dropdown_label">About <strong>Us</strong></div>
<div class="dropdown_content">
<ul>
<li>Contact</li>
<li>Facts and Figures</li>
<li>Offices</li>
</ul>
</div>
</div>
Both the dropdown label and the dropdown content are contained within the dropdown. It sounds like you only want your effect to execute when the user mouses over the dropdown label.
Edit
Some untested JavaScript that may or may not work
$$('DIV.dropdown').each(function(dd) {
var dd_list = dd.down('.dropdown_content');
dd.select('DIV.dropdown_label').each(function(ddl) {
ddl.observe('mouseover', function(event){
console.log('mouseover');
dd.addClassName('dd_open');
});
});
dd.observe('mouseout', function(event){
console.log('mouseout');
dd.removeClassName('dd_open');
});