Jquery - Difference between event.target and this keyword? - javascript

What is the difference between event.target and this?
Let's say I have
$("test").click(function(e) {
$thisEventOb = e.target;
$this = this;
alert($thisEventObj);
alert($this);
});
I know the alert will pop different value. Anyone could explain the difference? Thanks a million.

They will be the same if you clicked on the element that the event is rigged up to. However, if you click on a child and it bubbles, then this refers to the element this handler is bound to, and e.target still refers to the element where the event originated.
You can see the difference here: http://jsfiddle.net/qPwu3/1/
given this markup:
<style type="text/css">div { width: 200px; height: 100px; background: #AAAAAA; }​</style>
<div>
<input type="text" />
</div>​
If you had this:
$("div").click(function(e){
alert(e.target);
alert(this);
});
A click on the <input> would alert the input, then the div, because the input originated the event, the div handled it when it bubbled. However if you had this:
$("input").click(function(e){
alert(e.target);
alert(this);
});
It would always alert the input twice, because it is both the original element for the event and the one that handled it.
​

Events can be attached to any element. However, they also apply to any elements within said object.
this is the element that the event is bound to. e.target is the element that was actually clicked.
For example:
<div>
<p>
<strong><span>click me</span></strong>
</p>
</div>
<script>$("div").click(function(e) {
// If you click the text "click me":
// e.target will be the span
// this will be the div
}); </script>

Crispy answer
this gives you the reference of the DOM element where the event is actually attached.
event.target gives you the reference of the DOM element where the event occurs.
Long answer
jQuery(document).ready(function(){
jQuery(".outer").click(function(){
var obj = jQuery(event.target);
alert(obj.attr("class"));
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="outer">
Outer div starts here
<div class="inner">
Inner div starts here
</div>
</div>
When you run the above code snippet you will see that event.target is alerting the class name of the div that is actually clicked.
However this will give the reference of the DOM object on which the click event is bind. Check the below code snippet to see how this works, always alerting the class name of the div on which the click event is bind even if you click the inner div.
jQuery(document).ready(function(){
jQuery(".outer").click(function(){
var obj = jQuery(this);
alert(obj.attr("class"));
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="outer">
Outer div starts here
<div class="inner">
Inner div starts here
</div>
</div>

Related

Event propagation issue

I have a series of click events which are causing me some propagation issues. The data for this container is loaded in via ajax hence the body on click method. Here's the code I have:
$(function () {
$("body").on("click","#top-div",function(){
console.log("top event");
});
$("body").on("click","#middle-div",function(e){
e.stopPropagation();
});
$("body").on("click","#bottom-div",function(){
console.log("bottom event");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="top-div">
top
<div id="middle-div">
middle
<div id="bottom-div">
bottom
</div>
</div>
</div>
The top div has an event which the middle one needs to not inherit hence the stopPropagation(). However the bottom one needs to have an event of its own but the stopPropagation() from the middle one is stopping it from executing the event (if I remove the stop propagation the bottom event triggers but coincidentally so does the top)
How can I get around this bubbling issue?
I think what you want to happen is that the propagation is only stopped if it originated from the middle div; if it originated from the bottom div you want the event to bubble all the way to the top.
You need to call stopPropagation conditionally. If the event did not originate on or inside #bottom-div, you want to call it. You can test for this using closest:
if (!$(e.target).closest('#bottom-div').length) {
e.stopPropagation();
}
It is better to use closest for this, rather than testing the element's id directly, because with closest it will continue to work as expected even if there are other elements (a or em, for example) within the various divs.
$(function () {
$("body").on("click","#top-div",function(){
console.log("top event");
});
$("body").on("click","#middle-div",function(e){
if (!$(e.target).closest('#bottom-div').length) {
e.stopPropagation();
}
});
$("body").on("click","#bottom-div",function(){
console.log("bottom event");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="top-div">
top
<div id="middle-div">
middle
<div id="bottom-div">
bottom
</div>
</div>
</div>
Bubbling works from most nested element to tree root, I think You misunderstanding it in some way. So for example click in bottom-div will:
call event on bottom-div --> call event on middle-div --> call event on top-div.
As I understand the need You want to some how check what div was clicked, so to have control on it just create single event and check clicked target like that:
$("body").on("click","#top-div",function(e){
if ( e.target.id ==='top-div'){
//click in top div
}
if ( e.target.id ==='middle-div'){
//click in middle div
}
if ( e.target.id ==='bottom-div'){
//click in bottom div
}
});
In this proposition You know exactly which div was clicked, but it will always be the most nested one, so target will be middle-div only when will be clicked part of middle-div which is not bottom-div, it will be for example padding space, the same is with top-div it will be target only if click will be in space without child elements.
More about event bubbling You can find in http://maciejsikora.com/standard-events-vs-event-delegation/.
Instead of attaching event to every div. You can consider doing it as follows
check this snippet
$(document).ready(function() {
$("body").on("click", "div", function(event) {
console.log(event.currentTarget.id + "event");
if (event.target.id === "middle-div") {
event.stopPropagation()
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="top-div">
hello
<div id="middle-div">
hi
<div id="bottom-div">
bott-mid-v
</div>
</div>
</div>
Hope it helps

How to embed a clickable div inside another clickable div

In a previous question I asked about toggling a child div from the parent which was answered and the answer given works. Now I have a different issue: When I click anywhere within the inner (such as the link "inside inner div" it causes the outer div to toggle. I want the inner div to toggle only by itself. If I click as described, then div containing "This is the inner div" should disappear but the class openData should be active for the outer div. Instead it gets set to closeData.
This is my code:
<html>
<head>
<style>
.openData{font-size:18px;background-color:lightgreen;color:blue;}
.closeData{font-size:18px;background-color:lightblue;color:blue;)
</style>
<script src="/js/jquery.js"></script>
<script>
function insideDiv(f) {
var e=window.event;
e.cancelBubble=true;
e.stopPropagation();
toggleDiv(f);
return false;
}
function setCursor(e) {
e.style.cursor="pointer";
}
function clearCursor(e) {
e.style.cursor="default";
}
function togglePlusMinus(f) {
$(f).children('div:first').toggle();
$(f).toggleClass("openData closeData");
}
</script>
</head>
<body>
<div class="closeData" onmouseover="setCursor(this);" onmouseout="clearCursor(this);" onclick="togglePlusMinus(this);">This is the outer div
<p>Inside outer div</p>
<div style="display:none;;background-color:#ffffff;" onclick="insideDiv(this);">This is the inner div
<div>
<p style="margin-left:20px;margin-top:0px;font-size:15px">inside inner div</p>
</div>
</div>
<p>Also in outer div</p>
</div>
This is just some trailing text.
</body>
</html>
Everything I've read says that I need to stop the click propagation (which I think I am doing correctly).
This is the smallest working failure example. The actual program shows expandable data sets nested within each other.
Try adding an eventListener to your inner div and use stopPropagation like in the parent.
var myDiv = document.querySelector('#myDiv'); //assuming your child div has a "myDiv" id
myDiv.addEventListener(pEvent) {
pEvent.stopPropagation();
};
EDIT :
To make it work with every first child div of each .closeData element you can do (assuming you have only one direct child div):
//Selects all .closeData elements
var parents = document.querySelectorAll('.closeData');
//For each .closeData, find the first div and stops the propagation
for(var i = 0; i < parents.length; i++) {
var child = parents[i].querySelector('div');
child.addEventListener('click', function(pEvent) {
pEvent.stopPropagation();
})
}
Edit: it seems that the problem is that you are calling stopPropagation to the window event, not the actual element that you are clicking.
You are looking most likely for the event bubbling tutorial (at least if I understood correctly). Please check this out as it describes your problem:
http://javascript.info/tutorial/bubbling-and-capturing
And in shorthand to stop the inner event to propagate to outer div use:
event.stopPropagation()
and for IE9 earlier:
event.cancelBubble = true
If only the outer div function is firing try setting a z-index on the inner div that is higher than the parent div.
Explicitly pass event to your function such that
Onclick="function(event || window.event, this)"
Then add a a param for the event on your function and do event propagation cancelation on that.

Disable contextmenu for a specific container and its children

I need to disable contextmenu only inside a specific div #wrapperand its children, and not the whole page. This is what I'm doing:
document.addEventListener('contextmenu', function (event) {
console.log(event.target.id);
if (event.target.id === 'wrapper') {
event.preventDefault();
}
});
.. but it doesn't seem to work.
You're approaching this the wrong way: you're adding the listener to the document, which may be ok, but it's easier to add it to the element itself, and you are checking event.target.id, which is the ID of the current clicked element (e.g. a children of your wrapper), not the wrapper.
To make this work you can easily do something like this instead:
var myWrapper = document.getElementById('wrapper');
myWrapper.addEventListener('contextmenu', function(e) {
e.preventDefault();
}, true);
This is a solution that work fine
<div id="wrapper" oncontextmenu="return false">
#wrapper
<div class="childds">
</div>
The code you have in your question works perfectly. One possibility of why the context menu still showed up is that you in fact clicked on a child of #wrapper, instead of clicking on the element itself:
HTML
<div id="wrapper">
#wrapper
<div class="inner">
#wrapper .inner
</div>
</div>
Working example demonstrating this issue on JSFiddle.
You can overcome this by attaching the event handler to the desired element directly instead. This way, right-click events on child-elements will bubble up to #wrapper, and thus fire the event as expected:
JavaScript
document.getElementById('wrapper').addEventListener('contextmenu', function (event) {
event.preventDefault();
});
Working example on JSfiddle.

different types of jQuery selectors

What’s the difference between $(“#foo .bar”) and $(“#foo”).find(“.bar”)?
$('#foo').on('click', function(){
$(this).find('.bar').css('background-color', 'yellow');
})
$('#foo_two .bar_two').on('click', function(){
$(this).css('background-color', 'red');
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id = "foo">
<p class= 'bar' style='background: green'> Hello there</p>
</div>
<div id = 'foo_two'>
<p class = 'bar_two' style='background: orange'> Hello there</p>
</div>
In the snippet, I tried to outline what I thought was the difference but seem to now not know what's going on...
$('#foo').on('click', function(){
means that the parent #foo is the click target Element
$('#foo_two .bar_two').on('click', function(){
... click on the parent #foo_two if you dare! http://jsfiddle.net/0qcssuue/2/
(.bar_two has now the click event bound to it. #foo_two just helped jQuery and the JS parser to find it's child .bar_two Element)
To conclude, the $(this) inside the function refers to the targeted Selector.
In the first case it's #foo,
in the second it's #foo_two .bar_two (the #foo_two's children .bar_two)
In your case you could not notice the difference cause the parent was wrapping so close the child element that every click seemed to target the same selector. Adding some padding to the parent (like in my demo) makes the difference more clear.
The difference is in which object you are attaching the listener for click event.
For case:
$('#foo').on('click', function(){
$(this).find('.bar').css('background-color', 'yellow');
})
You are attaching the listener to the #foo object.
For case:
$('#foo_two .bar_two').on('click', function(){
$(this).css('background-color', 'red');
})
You are attaching the listener to the #foo_two .bar_two object
I adjust your fiddle to show the difference. Green label changes when you click de div element but orange label changes when you click the p element
http://jsfiddle.net/0qcssuue/3/

jquery event bubbling and event.targets

I'm trying to get my head around how to stop a click event from bubbling up,out,down when a particular element is clicked.
<div class="clickable">
clicking here shouldn't affect parents or children
<div class="clickable">
clicking here shouldn't affect parents or children
<div class="clickable">
clicking here shouldn't affect parents
</div>
</div>
</div>
Basically, if an element with the class "clickable" is clicked, I only want that item to be affected, toggling an even/odd class.
Here's the fiddle: http://jsfiddle.net/LDaA7/
When you run the fiddle and click a particular item, you'll see that various parents and children also get toggled.
From experimenting, event.stopPropagation(), returning false/true, .one, etc. impacts click events not targets per se. I may want other (unrelated) click events to work.
How do I target only the element I'm clicking?
You can just check if the target equals the bound element (this):
$("body").on "click", ".clickable", (event) ->
if this is event.target
clickTarget = $(event.currentTarget).closest(".clickable")
clickTarget.addClass "clicked"
if clickTarget.hasClass "odd"
clickTarget.addClass("even").removeClass("odd")
else
clickTarget.addClass("odd").removeClass("even")
FIDDLE
You want to use $(this) to target the element you have clicked. Also, .stopPropagation() so it won't bubble up the events.
See Demo here
$('.clickable').click(function (e) {
e.stopPropagation();
var elem = $(this);
elem.addClass('clicked');
if (elem.hasClass('odd')) {
elem.addClass('even');
elem.removeClass('odd');
} else {
elem.removeClass('even');
elem.addClass('odd');
}
});

Categories