'onClick' event on div not happening when there are child elements present - javascript

I'm building a new website for myself, looks like this..
HTML
<div id="row1">
<div class="orange" onClick="itemLoad()">
<img src="img/game/wacky.jpg" width="140" />
<p><strong>A Day At The Races (2014)</strong><br>
3 x 8-bit instruments</p>
</div>
<div class="blue" onClick="itemLoad()">
<img src="img/game/dott.jpg" width="140" />
<p><strong>Back to the Mansion! (2013)</strong><br />
fl, ob, cl, bsn, xyl, vibes, vln, vla, vlc.</p>
</div>
.... etc etc etc.
CSS (all boxes have identical CSS except the background colour)
.orange{
width:150px;
height:150px;
background:#F90;
display:inline-block;
margin:10px;
cursor:pointer;
box-shadow:#CCC 4px 4px 4px;
border-radius: 10px;
padding:10px;
font-family:Arial, Helvetica, sans-serif;
font-size:11px;
line-height:1.5;
}
Basically, when you click on one of the boxes, it shows a content DIV telling you about that piece of music, based on the row it's in.
JQuery
function itemLoad(){
if($(event.target).parent().is("#row1")){
$("#row1content").fadeIn("slow");
}else if($(event.target).parent().is("#row2")){
$("#row2content").fadeIn("slow");
}
}
This function works absolutely fine when the boxes are empty, but when they have content in them as you seen in the picture, the function only runs when I click around the padding. I've never had this problem before. Any help would be appreciated :)

event.target is the clicked element, and when you click a child element, that's what event.target is, so it's not consistently giving you the right element, or the right parent element, as event.target does not reference the element the event handler is bound to, but the element the event originated from.
Also, you're relying on the global event, which is not cross-browser.
What you want to do is use proper event handlers, and this
$('.blue, .orange').on('click', function() {
if ( $(this).parent().is("#row1") ){
$("#row1content").fadeIn("slow");
} else if ( $(this).parent().is("#row2") ){
$("#row2content").fadeIn("slow");
}
});
It should be noted that there most definitively is a more dynamic way to do that, giving all the targeted elements the same class, and then fading based on index or position in the DOM, without targeting each element based on the parents ID.

This is what I had in mind :)
function itemLoad(event) {
if ($(event.target).parents().is("#row1")) {
$("#row1content").fadeIn("slow");
} else if ($(event.target).parents().is("#row2")) {
$("#row2content").fadeIn("slow");
}
}

Related

How to make a tooltip without needing any child elements

I've been trying to make a tooltip that activates upon hovering an <a> tag and displays a <div> from another place
Example:
<p>
blah blah <a class="tooltiphover">hover me</a> blah blah
</p>
<div class="tooltip">
<!-- tooltip info code goes here -->
</div>
But every tutorial and site I've stumbled upon has been adamant on using child elements and biggest problem with that is it makes the code look bad or forces me to use a <div> tag which then screws up the look of the site
Example:
<div class="tooltiphover">Hover me</div>
<span class="tooltip">Tooltip stuff</span>
</div>
Especially when it comes to their css with .tooltiphover:hover .tooltip.
Also if there is any way to call for both elements in css to be modified when one is hovered, without being a child element, that would be great as well because adding a comma doesn't seem to do the trick and neither does adding a plus
Thanks.
EDIT: Actually, to make it simpler, how would I make the div appear in front of everything and appear next to the <a> tag like a proper tooltip because I might just use JS to deal with the mouseover event. To be honest, not sure why I went through the effort of trying to use CSS and HTML for this when it is a lot easier with JS, but I think it was probably due to all the tooltip tutorials I searched up confused me too much 😅
What would be the CSS code for that?
There are multiple ways to accomplish this, and note that none specifically require a <div> tag. CSS has many different types of selectors with different rules for how each behave. Generally speaking, CSS cascades and interacts forwards, meaning it can be difficult to interact with elements prior in your document (i.e. a child telling its parent how to behave is rare.)
The most common type of selector for this is either the element element selector or the element > element selector. They require the affected/target element be a child of the parent element.
They look something like this.
div:hover > h2{
display:block;
}
h2{
display:none;
}
<div>hover me
<h2>i am revealed</h2>
</div>
<p>don't hover me</p>
However, as you said, this requires a highly coupled relationship between the element you are selecting for and its parent. This is where the element ~ element selector comes into play.
div:hover ~ h2{
display:block;
}
h2{
display:none;
}
<div>hover me</div>
<p>don't hover me</p>
<h2>i am revealed</h2>
Where element > element requires a vertical relationship between your parent and child, element ~ element requires a horizontal sibling relationship. In the example given, all elements matching your selection would be revealed so long as they are siblings within the same context.
But what would happen if your desired target was a child of a sibling, rather than the sibling itself?
div:hover ~ h2{
display:block;
}
h2{
display:none;
}
<div>hover me</div>
<p>don't hover me</p>
<article>
<h2>i am revealed</h2>
</article>
Oh no! It doesn't work now, because they are no longer siblings within the same context. There are many ways to solve this issue, both general and specific, but one simple way is as follows:
div:hover ~ * h2{
display:block;
}
h2{
display:none;
}
<div>hover me</div>
<p>don't hover me</p>
<article>
<h2>i am revealed</h2>
<article>
By combining the element ~ element selector with the * element selector, we can interact with any h2 that is a child of any sibling of our original selector with the :hover pseudo-class.
If I am understanding the second part of your question correctly, and you want both the hover element AND its target to change in some way when the hover event takes place, it's as simple as separately declaring the styles.
div:hover ~ * h2{
display:block;
}
div:hover{
color: red;
}
h2{
display:none;
}
<div>hover me and i turn red</div>
<p>don't hover me</p>
<article>
<h2>i am revealed and not red</h2>
<article>

How to make changes on the leaf node while not affecting the parent

All elements in the page are assigned to change background color and change border properties if hovered, but the problem is that the element I only want to change is the element directly under the cursor, It seems that when I hover something , all the parents of it is also hovered which is normal because you are also hovering to the parent of an element since its child is nested inside it.
But I found out that firefox screenshot feature can do this thing. It has a feature that lets you screenshot a certain part of the page, and in the selection process , It shows what part of the page is only saved by making a dashed border around it and a white overlay.
I think this has to do something with javascript but I don't know how to
Check if the element is hovered
Check if element is the one under the cursor by checking it's child if it's hovered.
Where to start checking things.
Let's say
<div>
<div> put border on me if hovered </div>
<div> put border on me if hovered
<span> put border on me if hovered and don't put border on parent </span>
</div>
</div>
Css
*:hover { border: 5px dashed white; }
I haven't made the javascript because I am stuck of what to do first
if you want that when you hover over a specific element, its style has changed,I can offer to do this with the help of JS
document.addEventListener('mouseover', function (e) {
e.stopPropagation();
e.target.setAttribute('style', 'border: 5px dashed red');
});
document.addEventListener('mouseout', function (e) {
e.target.removeAttribute('style');
});
You can change the style, in different ways, for example add a specific class. I hope this helps
So You want, when you hover on a particular div, that particular div must have border not the parent one.
So easy task can be achieved my CSS easily. you have to target the div's based on their className.
( Based on your code divs above )
<div>
<div className="parentBorder"> put border on me if hovered </div>
<div>
<span> put border on me if hovered and don't put border on parent </span>
</div>
</div>
The CSS File for this
.parentBorder {
border: none;
}
.parentBorder:hover {
border: 5px solid green;
}
span {
border: none;
}
span:hover {
border: 5px solid blue;
}
This will solve you problem
And by JAvaScript you can do this by initiating the onClick() Function event on the particular div for this task

How do you make a textbox input autcomplete/autosuggest that shows the first match inside the textbox, rather than a list?

I've found several samples of autocomplete/autosuggest, but the way they implement it is by showing a list below the textbox that you later need to click or select. I'd like to show the closest match inside the textbox itself as the user is typing, so that they can later press tab (or whatever) to fill the rest of the entry.
I think I got the logic down on how to do this in Javascript (via Vue JS), but I cannot figure out how this would be displayed inside the input. The suggestion would be slightly dimmer in colour, like the text you see on a "placeholder", and will be overwritten as the user keeps typing.
Any suggestions?
You can just position it absolutely, with a low z-index.
<div class="container">
<input v-model="value" #keyup.prevent="autofill"></input>
<div class="suggested">
{{suggested}}
</div>
</div>
input {
border: 4px solid #e3e3e3;
padding:10px;
width:100%;
}
.container {
width:50%;
margin: auto;
position:relative;
}
.suggested {
position:absolute;
top:25px;
left:25px;
color:#e3e3e3;
z-index:-1;
}
working example: https://codepen.io/ellisdod/pen/mdJayxo

Problems with bubbling event on dragleave

I have a working example with dragenter and dragleave events that highlight an area where the file should be dropped. This example works correctly.
Right now if I just add a single <span> inside of my dragenter region, highlighting does not work correctly anymore (when you hover the image on top of the text - highlighting disappears). As you see dragleave is called multiple times.
All I changed is substituted Drop files here to <span>Drop files here</span>
Also there is knockout code there, but I believe that it has nothing to do with the bug. I understand that the problem is with event bubbling, but
e.stopPropagation();
e.preventDefault();
return false;
does not help. Any idea how to make it work with dom elements indside?
P.S. this is just a simplified example and it looks like I was not able to properly make it (I was thinking that the only way to solve it through JS, and it appears that the way I described it it is possible to solve it with css as well). Sorry for this confusion. Example looks more like this. Not only the Text is inside of the dropable element, but when you drop something, elements appears there. These elements are clickable.
The problem with Malk's solution is that :after element stays on top of these clickable elements and thus making them unclickable.
It looks like you can attach the handlers to an overlay div that is positioned after and on-top-of the span:
<div class="col-md-12" data-bind="foreach: dropZones">
<div class="drop_zone">
<span>Drop files here</span>
<div class="drop_zone_overlay" data-bind="event:{
dragover: function(data, e){ $root.dragover(e);},
drop: function(data, e){ $root.drop(e, $data);},
dragenter: function(data, e){ $root.dragenter(e, $index());},
dragleave: function(data, e){ $root.dragleave(e, $index());}
}">
</div>
</div>
<ul data-bind="foreach: elements" style="height: 100px">
<li data-bind="text: $data"></li>
</ul>
</div>
CSS
.drop_zone {
border: 2px dashed #bbb;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
padding: 25px;
text-align: center;
font: 20pt bold'Vollkorn';
color: #bbb;
position:relative;
}
.drop_zone_overlay {
position:absolute;
top:0;
bottom:0;
left:0;
right:0;
}
http://jsfiddle.net/rWWK5/
EDIT
Actually you do not need to add another element at all. You can create a pseudo-element with CSS :after that should work to cover the content.
.drop_zone {
...
position:relative;
}
.drop_zone:after{
content:'';
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
}
http://jsfiddle.net/ewng9/
EDIT 2
You can use this technique to cover the contents only when dragging. You just need to change your .css({}) call to toggleClass() and put the :after on the new class.
http://jsfiddle.net/dKsmw/
This will also lets you create an overlay that tints the background elements:
.drop_zone_hover:after{
...
background-color:#0f0;
opacity:0.6;
}
I think Malk's answer is valid. Using an overlay or mask to sit above the drop zone and it's children when you drag over and drop. This prevents the issue you were experiencing with the span
I've created a working Fiddle with your newest example.

How to keep the background color persistent in css active?

I have a image, when user clicks on it I am changing the background color of it. for ex:
HTML:
<img src="images/image1.png" />
CSS:
img:active{
background-color:red;
}
But the red color is not persistent. and the red color is replaced with the old color. How can I make it persistent ?
OnClick functionality isn't achievable solely through CSS. You will need to use javascript to achieve this.
Just use jQuery:
$('img').click(function(){
$(this).addClass('red');
});
then in css make sure you have something like this:
img.red {
background-color:red;
}
As others pointed out, you should use javascript with onclick event handler, save the clicked element's state and toggle at right time... However I would like to introduce this work-around without using any script, it uses some focusable wrapper (like a button) to mimic other unfocusable element (like the image) and use the :focus pseudo-class to style the active element (as you understand, it can be in such a state by clicking or tabbing):
HTML:
<button class="wrapper">
<img/>
</button>
CSS:
.wrapper > img {
background-color:inherit;
width:200px;
height:200px;
}
.wrapper {
border:none;
padding:0;
cursor:default;
}
.wrapper:focus {
background-color:red;
outline:none;
}
Here is the working fiddle, try clicking the image and then clicking on some point outside to see it in action.

Categories