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"
Related
I want to apply styles to a parent element if only it doesn't contain a certain class child element in CSS. To make it understand better, I have made a demo,
.level-1 {
width: 400px;
background: green;
}
.level-3 {
color: white;
font-size: 32px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div>
<div class='level-1'>
<div class='level-2'>
<div class='level-3'>This is text 1</div>
</div>
</div>
<div class='level-1'>
<div class='level-2'>
<div class='level-3'>This is text 2</div>
</div>
</div>
<div class='level-1'>
<div class='level-2'>
This is text 3
</div>
</div>
</div>
</body>
</html>
In the above example scenario, I want all the elements under level-1 to take a width of 400px but if level-1 contains level-3 class name element, then I don't want the width of 400px.
I tried using the :not selector but couldn't do it, I tried doing like this,
.level-1:not(.level-3) {
width: 400px;
background: green;
}
I know I can do it via classList.contains in Javascript but I want to do it via CSS. Is there a way in which I could achieve the above requirement?
You could add another class in level 1 class to be more specific with your CSS selectors i.e. to apply width specific to those div elements which does not have a level-3 class name element.
.level-1.include {
width: 400px;
background: green;
}
.level-3 {
background: green;
color: white;
font-size: 32px;
}
<div>
<div class="level-1 include">
<div class="level-2">
<div class="level-3">This is text 1</div>
</div>
</div>
<div class="level-1">
<div class="level-2">
<div class="level-3">This is text 2</div>
</div>
</div>
<div class="level-1 include">
<div class="level-2">This is text 3</div>
</div>
</div>
I got the following problem.
I got an div with is filled with different elements and that has a mouserover-event. I need to use the div in the mouseover-function. The Problem is that i can't select the div via it's class because there are many automaticaly created divs with the same class.
I have tryed to use event.targetbut it returns the object that is inside the that that was used as selector.
$(".outer").on("mouseover",function(event){
alert("event.target.className is: " + event.target.className);
});
.inner{
background-color:#ccc;
min-width:100px;
width:100%;
min-height:100px;
height:100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class= "outer">
<div class="inner">
here
</div>
</div>
Is there any way to get the div outer on mouseover without selecting it by it's class?
I also can't just use $(event.target).parent() because there can be deeper nested structures inside the outer div that are dynamically created
The way I understood the question is you really want to use mouseover event on the .inner div(s). With the example you provided, what would happen if .outer div had padding for example? The event would still trigger even though we are not hovering over .inner div at all. So I would change the event attaching a little and use jQuerys .closest-method to travel back up to the parent div:
var $container = $(".outer");
$container.on("mouseover", ".inner", function(event) {
console.log($(this).closest(".outer").attr("class"));
// or since in this case you know it's the same element:
// console.log($container.attr("class"));
});
.outer {
padding-top: 30px;
background: Red;
}
.inner {
background-color: #ccc;
min-width: 100px;
width: 100%;
min-height: 100px;
height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="outer">
<div class="inner">
here
</div>
<div class="inner">
here 2
</div>
</div>
Hope, this would work for you:
$(".outer").on("mouseover",function(event){
alert("event.target.className is: " + $(event.target).parent().attr('class'));
});
.inner{
background-color:#ccc;
min-width:100px;
width:100%;
min-height:100px;
height:100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class= "outer">
<div class="inner">
here
</div>
</div>
Use this instade of event.target
this trigger current selector.
$(".outer").on("mouseover",function(event){
alert("event.target.className is: " + this.className);
});
Like this?
I don't understant why you can't use parent
Well, you can get the current listener object just by using "this"
$(".outer").on("mouseover", function(event){
var obj = $(this);
console.log(obj.hasClass("outer"))
});
.inner{
background-color:#ccc;
width:100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="outer">
<div class="inner">
here
</div>
</div>
<div class="outer">
<div class="inner">
<div>
<div>
<div>
<div class="someclass">
<div>
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
deeeeeeeep inside
</div>
</div>
</div>
</div>
</div>
there
</div>
</div>
Have you tried event.currentTarget
Example: http://codepen.io/camtullos/pen/bgQNoa?editors=1111
$(".outer").on("mouseover",function(event){
console.log(event.currentTarget.className);
});
I know the title is confusing but I wasn't sure how to phrase it.
fiddle: https://jsfiddle.net/jzhang172/xnem879m/1/
What I'm trying to accomplish:
When I click on the h3 element in each container, it turns into an "x" and lengthens the container and when I click on it again, it reverts back to its text and height.
However, my problem is if you click on another container after the initial one, it will grab that h3 element and apply it to the rest of the containers.
To reciprocate this problem, do this:
1.) Click on the first container
2.) Click on the second container
3.) Now click on the first container which will revert to its original height but now it has the second container's h3 element.
I see that my problem is that my first function is grabbing the h3 element but I'm really not sure how to fix this issue.
$("h3").one("click", function(){
window.h3title=$(this).text(); //Make global variable so next function has access to it.
console.log(h3title);
});
$("h3").click(function(){
if( $(this).parents(".work").height()<200){
$(this).stop().parents(".work").animate({height: '300px'}, {duration:500, complete:function(){
$(this).find('h3').text('X');
}
});
}//IF
else{
$(this).stop().parents(".work").animate({height: '100px'}, {duration:500, complete:function(){
$(this).find('h3').text(h3title);
}
});
}
});
.work{
background:blue;
height:100px;
width:100%;
}
h3{
color:red;
text-shadow:1px 1px 1px black;
cursor:pointer;
}
span{
color:white
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="work">
<h3>1 Click me</h3>
<span>I will Change</span>
</div>
<div class="work">
<h3>2 Click me</h3>
<span>I will Change</span>
</div>
<div class="work">
<h3>3 Click me</h3>
<span>I will Change</span>
</div>
<div class="work">
<h3>4 Click me</h3>
<span>I will Change</span>
</div>
<div class="work">
<h3>5 Click me</h3>
<span>I will Change</span>
</div>
The problem is that the global variable you're declaring (and it doesn't have to be global. All it has to do is be declared in a scope that's a parent to both function scopes.) is getting overwritten on every call, and every element that has access to it will use the last value it was set to.
E.g.
Store '1 Click me' in variable
Store '2 Click me' in variable
Restore text to first h3, which is now '2 Click me'.
The solution is to store the data in a context specific place. Since it's consistent, you can assign a data-index (or whatever you want to name it) to the element.
$("h3").click(function() {
if ($(this).parents(".work").height() < 200) {
$(this).stop().parents(".work").animate({
height: '300px'
}, {
duration: 500,
complete: function() {
$(this).find('h3').text('X');
}
});
} //IF
else {
$(this).stop().parents(".work").animate({
height: '100px'
}, {
duration: 500,
complete: function() {
var $h3 = $(this).find('h3');
$h3.text($h3.attr('data-index') + ' Click me');
}
});
}
});
.work {
background: blue;
height: 100px;
width: 100%;
}
h3 {
color: white;
text-shadow: 1px 1px 1px black;
cursor: pointer;
}
span {
color: white
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="work">
<h3 data-index="1">1 Click me</h3>
<span>I will Change</span>
</div>
<div class="work">
<h3 data-index="2">2 Click me</h3>
<span>I will Change</span>
</div>
<div class="work">
<h3 data-index="3">3 Click me</h3>
<span>I will Change</span>
</div>
<div class="work">
<h3 data-index="4">4 Click me</h3>
<span>I will Change</span>
</div>
<div class="work">
<h3 data-index="5">5 Click me</h3>
<span>I will Change</span>
</div>
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'.
you can view the following code on
jsfiddle too my full code is below
<html>
<head>
<title>Test Page</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<style>
.darkContent{
position: fixed;
background-color: white;
border: 5px solid black;
padding: 8px;
overflow: hidden;
color: #333;
font-family: arial;
}
.darkCover{
position: fixed;
left: 0px;
top: 0px;
z-index: 900;
background-color: black;
opacity: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
Show Box1
<form action="save.php" method="post">
<div id="useThisDiv1" width="500" height="500">
<h3 class="breadcrumb">Div TWO</h3>
<div class="row" id="popup3">
<div class="col-md-12">
<div class="portlet">
<div class="portlet-body">
<div class="row">
<div class="col-md-12">
<div class="form-group">
<textarea rows="2" cols="50" name="notification_text"></textarea>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 ">
<div class="portlet-body form">
<div class="form-body pull-right">
Cancel
save
<input type="submit" value="save" name="savethis">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
<script>
$(function(){
function darkBox(div){
var w = (div.attr('width')) ? div.attr('width') : div.width();
var h = (div.attr('height')) ? div.attr('height') : div.height();
var box = $('<div></div>').addClass('darkCover');
$('body').prepend(box);
box.fadeTo('fast', 0.8);
$(this).keydown(function(e){
if(e.keyCode == 27){
box.hide();
contentBox.hide();
}
});
var contentBox = $('<div></div>').html(div.html());
contentBox.addClass('darkContent');
var x = $(window).width()/2;
var y = $(window).height()/2;
var endTop = y - h/2;
var endLeft = x - w/2;
contentBox.css("left", endLeft+"px");
contentBox.css("top", endTop+"px");
contentBox.css("z-index", "910");
contentBox.css("width", w+"px");
contentBox.css("height", h+"px");
$('body').prepend(contentBox);
contentBox.show();
}
$('.darkBox').each(function(){
var div = $($(this).attr('data-target'));
div.hide();
$(this).click(function(){
darkBox(div);
});
});
$('.add_case_note_cls').click(function(){
alert('foo');
console.log('foo');
});
});
</script>
</body>
</html>
If i click on any of them three buttons I don't get any response what so ever, I've two anchor tags and one submit button, they're not working. Their click events are not registering I tried both by calling them with their class names like $('.classname).click(function(){alert('foo);}); and by using calling them id's like $('#cancelbtn).click(function(){alert('foo);});.
once again jsfiddle link
I don't know what i'm doing wrong here, any Idea?
The main problem here is that you're essentially cloning your HTML when you show it. I'm not sure if that's what you're intending to do or not, but that's what you're doing when you do var contentBox = $('<div></div>').html(div.html());. So when you initially bind your click handler to the elements with the add_case_note_cls class, that only applies to the elements that currently exist in the DOM. However, the elements that you end up seeing, are created during the execution of your darkBox() function, and therefore do not have a click handler attached.
There are a few ways that you could go about rectifying this.
Move the binding of the click handler to be within the darkBox() function. Maybe right at the end of it.
Switch to using .on() instead of .click() for attaching click handlers. This will allow you to use delegated events, which will allow the click handler to fire on elements that are added to the DOM later. So instead of $('.add_case_note_cls').click(function(){ you'd have something like $('body').on('click', '.add_case_note_cls', function(){.
Use the original HTML instead of cloning it. This may or may not be an option depending on what your ultimate goal is here. If you're trying to use the same base HTML, but copy it to multiple places, then this won't work. But if you're not, then you should be able to do it.
Also, it's not the cause of your problem, but you have a typo here <a href="javascrip:;" id="saveNotification". You're missing a "t".
And if you want your click handler to fire on both of the links and the button, you need to make sure that you have the appropriate class on all of them.