How can I get outer div target with event.target? - javascript

I'm making web service with javascript (and jQuery), and I'm trying to make custom menu.
But the main point is "Widget's ID which is clicked by user".
I want to return widget's id (like widget1 or widget2),
even if user pressed inner objects (img, textarea, etc.)
I tried event.target.id but it returns inner object's id, not outer div.
How could I solve this problem?
JavaScript and HTML :
$("#wrapper_widgets").bind("contextmenu", function(event) {
event.preventDefault();
alert(event.target.id);
});
<div id="wrapper_widgets">
<div id="widget1">
<img src="blablabla.png">
<textarea id="widget1_textarea">blablabla</textarea>
</div>
<div id="widget2" style="border: 1px solid blue; width: 500px; height: 100px;">
<p id="widget2_timedoc">asdasdasd</p>
</div>
</div>

The problem is event.target will refer to the element from which the event was originated from, so you will have to find the closest ancestor widget element
One easy solution is to use a class to all the widgets and target it
<div id="wrapper_widgets">
<div id="widget1" class="widget">
<img src="blablabla.png">
<textarea id="widget1_textarea">blablabla</textarea>
</div>
<div id="widget2" class="widget" style="border: 1px solid blue; width: 500px; height: 100px;">
<p id="widget2_timedoc">asdasdasd</p>
</div>
</div>
then
$("#wrapper_widgets").on("contextmenu", '.widget', function (event) {
event.preventDefault();
alert(this.id);
});
or
$("#wrapper_widgets").bind("contextmenu", function(event) {
event.preventDefault();
alert($(event.target).closest('.widget').attr('id'));
});

You can use .closest('div') with .prop() to get the immediate ancestor ID.
$(event.target).closest('div').prop('id')
Note : This would work only if there is no further nesting of <div>s inside wrappers.
$("#wrapper_widgets").bind("contextmenu", function (event) {
event.preventDefault();
alert($(event.target).closest('div').prop('id'));
});
$("#wrapper_widgets").bind("contextmenu", function (event) {
event.preventDefault();
alert($(event.target).closest('div').prop('id'));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrapper_widgets">
<div id="widget1">
<img src="blablabla.png">
<textarea id="widget1_textarea">blablabla</textarea>
</div>
<div id="widget2" style="border: 1px solid blue; width: 500px; height: 100px;">
<p id="widget2_timedoc">asdasdasd</p>
</div>
</div>

In the event function use
$(this).parent().prop('id')
to get the immediate parent's id of the clicked element. This will always return the immediate parent and not necessarily only divs but in your case it will work and return 'widget1' or 'widget2'.

Related

event.stopPropagation() not working - Capturing still passes on function

First of all - I'm a noob. Sorry if this question is basic enough.
Second - I tried to search and as I can see I applied the solution as instructed in other posts.
With that being said...
I have three sets of DIVs. Each set consists on 2 Divs(one inside another). On the OUTER div there's a function that is saying to make a border if it's clicked.
To see the error:
Click on the word OUTER.
Click on the word INNER.
The code is suppose to make a border only in the outer.
HTML
<html>
<head>
<title>Event Propagation</title>
<meta charset="UTF-8" />
</head>
<body onload="onLoad()">
<!--Squares 1-->
<div style="display:inline-block">
<div class="outer" style="height: 100px; width: 100px;">
Outer
<div class="inner" style="height: 50px; width: 50px;margin:20px">
Inner
</div>
</div>
</div>
<!--Squares 2-->
<div style="display:inline-block">
<div class="outer" style="height: 100px; width: 100px;">
Outer
<div class="inner" style="height: 50px; width: 50px;margin:20px">
Inner
</div>
</div>
</div>
<!--Squares 3-->
<div style="display:inline-block">
<div class="outer" style="height: 100px; width: 100px;">
Outer
<div class="inner" style="height: 50px; width: 50px;margin:20px">
Inner
</div>
</div>
</div>
</body>
</html>
The JS
<script>
function onLoad(){
const elOuter = document.querySelectorAll(".outer")
elOuter.forEach(element=>{
element.addEventListener('click', fnChangeColor,false)
})
}
function fnChangeColor(e){
e.target.style.border="1px solid black"
if (e.stopPropagation) {
e.stopPropagation()
} else {
e.cancelBubble = true
}
}
</script>
FYI - I solved the question creating events to the children attributing the e.stopPropagation on them. That worked. But I know that's not the best approach. If I have a div with 100 divs inside, that'll be a hell on earth.
this is because when you click on "Inner" e.target element is "Inner", not "Outer".
What you do seem to me to a try of understanding event delegation,
do it this way:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>xxx</title>
<style>
body > div { display:inline-block; }
.outer { height: 100px; width: 100px; background: lightgrey; }
.inner { height: 50px; width: 50px;margin:20px; background: lightblue; }
.bordering { border: 1px solid black; }
</style>
</head>
<body>
<div> <div class="outer"> Outer <div class="inner"> Inner </div> </div> </div>
<div> <div class="outer"> Outer <div class="inner"> Inner </div> </div> </div>
<div> <div class="outer"> Outer <div class="inner"> Inner </div> </div> </div>
<script>
document.body.onclick= e => {
if (!e.target.matches('.outer')) return // ignore other click events
e.target.classList.toggle('bordering')
}
</script>
</body>
</html>
or this way
document.querySelectorAll('.outer').forEach(el=>{
el.onclick=e=>{
// console.log(e.target.className)
if (!e.target.matches('.outer')) return // ignore other click events
e.target.classList.toggle('bordering')
}
})
In your code, there is only one event used and no way for any propagation.
when the user click on a .inner the event append on the .inner element an never on the .outer.
it's like a bubble following it's a bottom up way, not the reverse.
when the bubble finds a target code (an avent listener), there is no more propagation and the bubble burst.
If you want to see an event propagation you have to set 2 event listeners ( an that mean 2 bubles).
You can see that by adding a console.log(e.target.className) like here:
document.querySelectorAll(".outer, .inner") // => 6 event listeners
.forEach(el=>{ el.addEventListener('click', getClick , false) })
var counter = 0
function getClick(e)
{
console.log( `${++counter} - event listener is on : ${e.currentTarget.className}
clicked element is : ${e.target.className} `)
}
cClear.onclick=_=>{ counter = 0; console.clear() }
body > div { display:inline-block; }
.outer { height: 100px; width: 100px; background: lightgrey; }
.inner { height: 50px; width: 50px;margin:20px; background: lightblue; }
<div> <div class="outer"> Outer <div class="inner"> Inner </div> </div> </div>
<div> <div class="outer"> Outer <div class="inner"> Inner </div> </div> </div>
<div> <div class="outer"> Outer <div class="inner"> Inner </div> </div> </div>
<button id="cClear">clear console</button>
In this case we have one outer div - the parent, and the inner div - the children.
So - the issue to understand here is:
target: Who triggered the event.
currentTarget: the element that has the function set in.
When clicking the inner div, you are clicking the children - but the element that has the function is the parent. So - the function should change the currentTarget (the outer div), not the target (that's the inner div that was clicked).
Just had to change
e.target.style.border="1px solid black"
with
e.currentTarget.style.border="1px solid black"

Javascritpt change class to a div near to his grand-father

I want to dynamically change the class of the element #sidePanel from .compact to .expanded, in this code:
<div id="sidePanel" class="compact"></div>
<div id="topbar">
<div id="buttonContainer">
<div id="button"></div>
</div>
</div>
I'm stuck here, I can't apply the class to the correct <div>, I can just add the class to the topbar:
$(document).ready(function(){
$("#button").mouseover(function(){
$("this").parent().eq(2).addClass(".expanded").removeClass(".compact");
});
});
I also tried this:
$(document).ready(function(){
$("#button").mouseover(function(){
$("#sidepanel").addClass(".expanded").removeClass(".compact");
});
});
Your second example was pretty close. When you $.addClass() and $.removeClass(), or are referring to classnames outside of using a selector to target something, just reference the class name (no need for the leading .). Also JS (and CSS) are case-sensitive, so $('#sidepanel') won't target #sidePanel - the cases need to match.
$("#button").mouseover(function() {
$("#sidePanel").addClass("expanded").removeClass("compact");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<style>.expanded {color: red;}</style>
<div id="sidePanel" class="compact">sidepanel</div>
<div id="topbar">
<div id="buttonContainer">
<div id="button">button</div>
</div>
</div>
In your first example, $(this) is how you reference this in jQuery. If you put this in quotes, the word this is treated as a string literal instead. And since to use $.parent() you would need to go up 2 levels, you should use $.parents() with the ID of the parent you want to target, then use $.prev() to select the previous element, which is #sidePanel. So to traverse the DOM like that, this is how I would do it.
$("#button").mouseover(function() {
$(this).parents('#topbar').prev().removeClass('compact').addClass('expanded');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<style>.expanded {color: red;}</style>
<div id="sidePanel" class="compact">sidepanel</div>
<div id="topbar">
<div id="buttonContainer">
<div id="button">button</div>
</div>
</div>
Your problem is you used $("#sidepanel") instead of $("#sidePanel")
Here's a working example after the change is made:
$(document).ready(function(){
$("#button").on('mouseover', function(){
$("#sidePanel").addClass("expanded").removeClass("compact");
});
});
#topbar > div {
width: 100px;
height: 30px;
background: #ccc;
margin-top: 20px;
}
#sidePanel {
width: 100%;
height: 40px;
background: #ccc;
}
#sidePanel.expanded {
height: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="sidePanel" class="compact"></div>
<div id="topbar">
<div id="buttonContainer"></div>
<div id="button"></div>
</div>
first: the solution
$(document).ready(function()
{
$("#button").mouseover(function()
{
// class names - without the dot
$("#sidepanel").addClass("expanded").removeClass("compact");
});
});
then: why you were really close on your first attempt
$(document).ready(function()
{
$("#button").mouseover(function()
{
// $(this) selector uses the `this` keyword (not as a string)
$(this).parent().eq(2).addClass(".expanded").removeClass(".compact");
});
});

Closing all other DIVS while opening one

What I am trying to achieve is the following
There are two DIVS with dropdown. I need to close one while opening the other on click function.
I am also trying to mouseout once the event is out of the dropdown box.
I would like to close the DIV once the click even happens outside the dropdown box.
Following is the HTML
<div class="first-div" style="display:inline-block">
<a class="first-div-link"><h6>REGION</h6></a>
<div class="first-div-dropdown">
<p>Drop down test from first DIV</p>
</div>
</div>
<div id="second-div" style="display:inline-block; float:right">
<h6>REGISTER</h6>
<div class="second-div-dropdown">
<p>Drop down test from second DIV</p>
</div>
</div>
CSS is following
.first-div-dropdown, .second-div-dropdown{
background-color:#555;
color:white;
height:100px;
width:200px;
}
JS is following
$(document).ready(function(){
$('.first-div-dropdown').hide();
$('.second-div-dropdown').hide();
$('.first-div-link').on('click', function (event){
$('.first-div-dropdown').slideDown(300);
});
$('.second-div-link').on('click', function (event){
$('.second-div-dropdown').slideDown(300);
});
});
Is there any way to use this as a function to control multiple DOMs in the HTML? If so could someone assist me with the current example ?
Thanks
The path to follow here is use a common class on your items, you don't need to create new classnames if all will have the same styles and will perform the same action. Check this:
$(document).ready(function() {
$('.cont-div').on('click', 'a', function(e) {
e.preventDefault();
$('.div-dropdown').slideUp(300);
$(this).next('.div-dropdown').stop().slideToggle(300);
});
//To close if you click outside the container divs
$('body').on('click', function(e) {
if (!$(e.target).parents('.cont-div').length) {
$('.div-dropdown').slideUp(300);
}
})
});
body {
height: 600px;
background: #e1e1e1;
}
.cont-div {
display: inline-block;
vertical-align: top;
width: 50%;
}
.div-dropdown {
background-color: #555;
color: white;
height: 100px;
width: 200px;
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="cont-div">
<h6>REGION</h6>
<div class="div-dropdown">
<p>Drop down test from first DIV</p>
</div>
</div><!--
--><div class="cont-div">
<h6>REGISTER</h6>
<div class="div-dropdown">
<p>Drop down test from second DIV</p>
</div>
</div>
If you want to get more specific, you could assign a similar class to both menus, in the case below, I added 'dropdown-div' to the class for both menus and then simply added a trigger whenever you click on something that is not a link, it will hide the menus by calling $('.dropdown-div').hide();
$(document).ready(function(){
$('.first-div-dropdown').hide();
$('.second-div-dropdown').hide();
$('.first-div-link').on('click', function (event){
$('.first-div-dropdown').slideDown(300);
});
$('.second-div-link').on('click', function (event){
$('.second-div-dropdown').slideDown(300);
});
});
$(document).on('click', function(event) {
if (!$(event.target).closest('a').length) {
$(".dropdown-div").hide();
}
});
.first-div-dropdown, .second-div-dropdown{
background-color:#555;
color:white;
height:100px;
width:200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="first-div " style="display:inline-block">
<a class="first-div-link"><h6>REGION</h6></a>
<div class="first-div-dropdown dropdown-div">
<p>Drop down test from first DIV</p>
</div>
</div>
<div id="second-div" style="display:inline-block; float:right">
<h6>REGISTER</h6>
<div class="second-div-dropdown dropdown-div">
<p>Drop down test from second DIV</p>
</div>
</div>
You're dealing with state management within a collection. You have 2 dropdowns, but 3 states: dropdown one's state, dropdown two's state, and the collection of dropdowns' state.
Using jQuery, the most common way of handling this I've seen is to start by "resetting" the collection's state each time, by hiding all dropdowns on click.
Then, open the dropdown that is being targeted by the client. This can also be a bit easier if you use a single class to target the collection which also lends itself to be reusable across an infinite number of dropdowns.
<div class="first-div" style="display:inline-block">
<a class="dropdown-trigger"><h6>REGION</h6></a>
<div class="dropdown-menu">
<p>Drop down test from first DIV</p>
</div>
</div>
<div id="second-div" style="display:inline-block; float:right">
<a class="dropdown-trigger"><h6>REGION</h6></a>
<div class="dropdown-menu">
<p>Drop down test from second DIV</p>
</div>
</div>
JS:
$('.dropdown-trigger').click(function (event) {
event.stopPropagation();
var $menu = $(this).siblings('.dropdown-menu');
$('.dropdown-menu').not($menu).slideUp(300);
$menu.slideToggle(300);
});
$(document).click(closeDropdowns);
function closeDropdowns () {
$('.dropdown-menu').slideUp(300);
}
Working codepen: http://codepen.io/amishstripclub/pen/wzbEVo
You could try using toggle like this:
$(document).ready(function(){
$('.first-div-link').on('click', function (event){
$('.first-div-dropdown').toggle();
$('.second-div-dropdown').toggle();
});
$('.second-div-link').on('click', function (event){
$('.first-div-dropdown').toggle();
$('.second-div-dropdown').toggle();
});
});

Something like this.getelementbyid(id of element inside this div)

I am looking for way to change 'GetElementById' div inside the div, which I am targeting.
Here's the example:
Let's say I have this
<div onclick="runscript()">
<div id="insider">
</div>
</div>
<div onclick="runscript()">
<div id="insider">
</div>
</div>
<script>
function runscript(){
document.getElementById('insider').style.color='red';
}
</script>
If I would like to change exactly the same div, which I am clicking on, I could use this.style.color='red', but I need to change "insider" div inside exactly 'this' div I'm clicking on.
I am looking only for javascript solution, no jquery.
<div onclick="runscript(this)">
<div class="insider">
Sample text
</div>
</div>
Give the insider div a class name called insider and do this:
function runscript(object){
object.querySelector("div[class='insider']").style.color='red';
}
This works by passing the parent div to the runscript function with the keyword this. Then querySelector will try to find the element based upon the selector div[class='insider']. If found it will set the color of the text to red.
<div onclick="runscript(this)">
<div class="insider">
</div>
</div>
<div onclick="runscript(this)">
<div class="insider">
</div>
</div>
<script>
function runscript(object){
object.querySelector('.insider').style.color='red';
}
</script>
like in the comments above
id is an unique identifier - so it is not valid to have an id twice in your DOM
I recommend you to use addEventListener instead of the onclick attribute
I made a fiddle in pure javascript: http://jsfiddle.net/53bnhscm/8/
HTML:
<div onclick="runscript(this);">
<div class="insider"></div>
</div>
<div onclick="runscript(this);">
<div class="insider"></div>
</div>
CSS:
div {
border: 1px solid black;
height: 100px;
}
.insider {
border: 3px solid green;
height: 20px;
}
Javascript:
function runscript(x) {
x.firstElementChild.style.border = '1px solid red';
}

have parent div clickable with clickable child div

How do I do something like:
<div onclick="foo1()">
<div onclick="foo2()"></div>
</div>
When I do that and I click the child element, it still runs the foo1() function. How do I temporarily disable the parent element or something?
With jQuery, you can use this: http://api.jquery.com/event.stopPropagation/
I have created a working EXAMPLE for you
HTML
<div id="parent">
<div id="child"></div>
</div>
CSS (just to distinguish the two divs)
#parent {
background-color: black;
width: 220px;
height: 220px;
}
#child {
position:relative;
background-color: blue;
width: 110px;
height: 110px;
top:160px;
left:160px;
}
JavaScript ( include jQuery )
$(document).ready(function(){
$('#child').click(function() {
alert('Child');
if (!e) var e = window.event;
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
});
$('#parent').click(function() {
alert('Parent');
});
});
When you click on the child ONLY the action from the child is getting actioned.
You can modify my example as you like to achieve what you need.
Hope this works for you.
Yes, jQuery can solve your problem. See the code below:
<script src="jquery.js" type="text/javascript"></script>
<script>
function a()
{
alert('parent');
}
$(document).ready(function(){
$('#div2').click(function(e){alert('child');e.stopPropagation();})
})
</script>
<div onclick="a();" style="height:100px;width:100px;border:1px solid red">
<div id="div2" style="height:85px;width:85px;border:1px solid green">
</div>
</div>
You can try
<div onclick="foo1(event)">
parent
<div onclick="foo2(event)">child</div>
</div>
And
function foo1(e){
console.log('foo1', e)
}
function foo2(e){
e.stopPropagation();
console.log('foo2', e)
}
Demo: Fiddle

Categories