I have a problem with the onmouseover() event listener.
<div class="parent" onmouseover="myfunction()">
<div class="child"></div>
</div>
I trigger a javascript function whenever the mouse is hovering over the parrent, but whenever I'm hovering over the child, it doesn't register the onmouseover anymore.
Is there a workaround so the onmouseover() also gets triggered while hovering over its child elements, using pure Javascript?
Use mouseenter event instead, which doesn't bubble with children elements like mouseoverdoes.
In other words with mouseover the event will be attached to all the element children too, so when you hover a child the event will be fired as if we left the parent div.
Demo:
document.getElementById("test").addEventListener("mouseenter", function(event) {
var target = event.target;
console.log(target.id);
}, false);
.child {
min-width: 50px;
min-height: 50px;
padding: 10px;
display: inline-block;
background-color: yellow;
}
.parent {
padding: 20px;
background-color: red;
}
<div id="test" class="parent">
<div id="child1" class="child">1</div>
<div id="child2" class="child">2</div>
<div id="child3" class="child">3</div>
<div id="child4" class="child">4</div>
<div id="child4" class="child">5</div>
</div>
You can see in the above snippet that using mouseenter the event is always firing even if we hover over children and only the parent id is logged, as if we didn't leave it.
Mouseover demo:
You can see the difference here using mouseover event:
document.querySelector(".parent").addEventListener("mouseover", function(event){
console.log(event.target.id);
});
.child {
min-width: 50px;
min-height: 50px;
padding: 10px;
display: inline-block;
background-color: yellow;
}
.parent {
padding: 20px;
background-color: red;
}
<div class="parent">
<div id="child1" class="child">1</div>
<div id="child2" class="child">2</div>
<div id="child3" class="child">3</div>
<div id="child4" class="child">4</div>
<div id="child4" class="child">5</div>
</div>
Related
I have a div container having 4 divs each of height 100vh so it makes the container of 400vh.
So, what I want is to stop the scrolling in that particular container while not making them hidden because I want to redirect to them one by one.
It's simply like : .container{scroll: do nothing}
No problem with javascript as well...
let parent = document.getElementsByClassName("parent")[0];
parent.addEventListener('mousewheel',(event) => {
event.preventDefault();
});
.parent {
overflow: auto;
border: 2px solid;
height: 300px;
}
.child{
height: 100vh;
background: yellow;
margin-bottom: 20px;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
Given the html and css below, is it possible to have a .child with class selected appear on top of other .child elements? I'd like if you can give an answer that would not change html structure and css position property of .child and .parent.
Also would be great to not toggle anything on parent, it is better to toggle child classes or styles, for parent it is better to set it once.
.parent {
position: absolute;
}
.child {
position: relative;
}
<div>
<div>
<div class="parent">
<div class="child selected"></div>
</div>
<div class="parent">
<div class="child"></div>
</div>
</div>
</div>
Greatly appreciate any input, thank you.
If you really want to stick to this HTML structure you could as example hide all elements (children) and show them only when they are selected.
A better solution would be having the selected class on the parent so then you could just simply give the selected parent a higher z-index.
Here you can find a snippet of how you can toggle the display without touching the HTML
// for demo purpuses
var toggleLayer = function() {
var next = $('.child.selected').removeClass('selected').closest('.parent').next();
var element = next.length ? next : $('.parent:first-child');
element.find('.child').addClass('selected')
}
.parent {
position: absolute;
}
.child {
position: relative;
display: none;
}
.selected {
display: block;
}
/* for demo purpuses */
.child {
height: 100px;
width: 100px;
line-height: 100px;
text-align: center;
background: red;
}
button {
position: fixed;
top: 120px;
left: 10px;
}
<div>
<div>
<div class="parent">
<div class="child selected">1</div>
</div>
<div class="parent">
<div class="child">2</div>
</div>
<div class="parent">
<div class="child">3</div>
</div>
<div class="parent">
<div class="child">4</div>
</div>
</div>
</div>
<!--- FOR DEMO PURPUSES --->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button onClick="toggleLayer()">Toggle layer</button>
I have a basic drag and drop trello-like kanban board. You can drag tasks between different grey boxes. It uses HTML drag and drop API found here https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API.
var dropTarget = document.querySelector(".drop-target");
var draggables = document.querySelectorAll(".drag-task");
// Tells the other side what data is being passed (e.g. the ID is targeted)
draggables.forEach(item => {
item.addEventListener("dragstart", function(ev){
ev.dataTransfer.setData("srcId", ev.target.id);
});
})
// The end destination, prevent browsers default drag and drop (disabling breaks feature)
// because it's disabled by browsers by default
dropTarget.addEventListener('dragover', function(ev) {
ev.preventDefault();
});
// End destination where item is dropped into
dropTarget.addEventListener('drop', function(ev) {
ev.preventDefault();
let target = ev.target;
let droppable = target.classList.contains('drag-box');
let srcId = ev.dataTransfer.getData("srcId");
if (droppable) {
ev.target.appendChild(document.getElementById(srcId));
}
});
/***********DRAGGABLE BACKGROUND ****************/
.drag-box {
background-color: lightgray;
float: right;
width: 120px;
min-height: 50px;
padding-bottom: 30px;
height: auto;
margin: 30px;
}
.drag-task {
background-color: white;
margin: 15px;
}
.drop-active {
border: 1px dashed red;
}
<div class="drop-target">
<div class="drag-box">
<div class="drag-card">
<div draggable="true" id="task1" class="drag-task">Test Card 1</div>
</div>
<div class="drag-card">
<div draggable="true" id="task2" class="drag-task">Test Card 2</div>
</div>
<div class="drag-card">
<div draggable="true" id="task3" class="drag-task">Test Card 3</div>
</div>
</div>
<div class="drag-box">
</div>
<div class="drag-box">
</div>
</div>
What I want to do to achieve is an effect similar to this gif found here. This creates another <div> element on the same level as drag-card class on a draghover effect, and repositions itself accordingly.
I know I have to use dragover and dragleave event listeners but that's as far as I got. I added this code at the end of the file. I have never used drag event listeners so this is new to me.
var makeHoverElement= true;
dropTarget.addEventListener("dragover", function(ev){
if(makeHoverElement){
let newNode =document.createElement('div');
newNode.className ='drop-active'
ev.target.parentElement.prepend(newNode);
makeHoverElement = false;
}
});
dropTarget.addEventListener("dragleave", function(ev){
// really I have no idea how to make this effect
});
Results so far have not turned out as I expected. Dragover is applying to element where the task item originated from
The problem is in ev.target.parentElement.prepend(newNode);
Your ev.target is still a child of the node you are dragging it from. That's why the dotted border div gets added to the 'old' box. I suggest that in your 'dragover' function you explicitly find the element the mouse is over and add your newNode to it. For example, you can select it by document.querySelector(":hover" ) or try to handle 'mouseover' events there.
As for the 'dragleave' effect, I suggest you clone your ev.target with Node.cloneNode() method and append the clone to the ev.target.parentElement using Node.insertBefore().
MDN on .insertBefore()
Using jquery and jquery UI, I did something quite like this a while ago. I didn't create a "make new card" function, I began with a "launchpad" and created two droppable areas that cards could be appended to and switched between - similar to what you have. Using "intersect" as I remember was a tipping point to getting it to work as I wanted - being able to move elements up and down the list (so they don't necessarily move back to where they originated). Perhaps it could be a starting point for you?
Here's the fiddle (the jquery is old.. recommend updating to newer versions)
Hope this helps.
EDIT: I made a couple of small tweaks to your code to add an outline and change the cursor on move. According to a comment on another question, adding a border is the most efficient way to create the visual 'outline' effect. There is a longer way to create the 'sortable' effect which is demoed in this codepen I found, and explained simply, the function is based around calculating hover position and if the dragged element is half-way over an item in the list, the effect displays and the item can be dropped in between list items.
Hope this is clear enough!
// Tells the other side what data is being passed (e.g. the ID is targeted)
var dropTarget = document.querySelector(".drop-target");
var draggables = document.querySelectorAll(".drag-task");
// Tells the other side what data is being passed (e.g. the ID is targeted)
draggables.forEach(item => {
item.addEventListener("dragstart", function(ev) {
ev.dataTransfer.setData("srcId", ev.target.id);
});
})
// The end destination, prevent browsers default drag and drop (disabling breaks feature)
// because it's disabled by browsers by default
dropTarget.addEventListener('dragover', function(ev) {
ev.preventDefault();
});
// End destination where item is dropped into
dropTarget.addEventListener('drop', function(ev) {
ev.preventDefault();
let target = ev.target;
let droppable = target.classList.contains('drag-box');
let srcId = ev.dataTransfer.getData("srcId");
if (droppable) {
ev.target.appendChild(document.getElementById(srcId));
}
});
.drag-box {
background-color: lightgray;
float: left;
width: 120px;
min-height: 80px; /*lengthened the height slightly*/
padding-bottom: 30px;
height: auto;
margin: 30px;
cursor: move; /*added the 'cross' cursor*/
}
.drag-task {
background-color: white;
margin: 10px;
padding: 5px; /*added padding to make tiles bigger*/
border:1px dashed #000000; /*set an outline*/
}
.drop-active {
border: 1px dashed red;
cursor: pointer; /*change the pointer back to the default cursor while moving between lists*/
}
<div class="drop-target">
<div class="drag-box">
<div class="drag-card">
<div draggable="true" id="task1" class="drag-task">Test Card 1</div>
</div>
<div class="drag-card">
<div draggable="true" id="task2" class="drag-task">Test Card 2</div>
</div>
<div class="drag-card">
<div draggable="true" id="task3" class="drag-task">Test Card 3</div>
</div>
</div>
<!-- added tiles to the 2nd list (and deleted 3rd box)-->
<div class="drag-box">
<div class="drag-card">
<div draggable="true" id="orange" class="drag-task">Orange</div>
</div>
<div class="drag-card">
<div draggable="true" id="apple" class="drag-task">Apple</div>
</div>
<div class="drag-card">
<div draggable="true" id="pear" class="drag-task">Pear</div>
</div>
</div>
$("#launchPad").height($(window).height() - 20);
var dropSpace = $(window).width() - $("#launchPad").width();
$("#dropZone").width(dropSpace - 70);
$("#dropZone").height($("#launchPad").height());
$(".card").draggable({
appendTo: "#launchPad",
cursor: "move",
helper: 'clone',
revert: "invalid",
});
$("#launchPad").droppable({
tolerance: "intersect",
accept: ".card",
activeClass: "ui-state-default",
hoverClass: "ui-state-hover",
drop: function(event, ui) {
$("#launchPad").append($(ui.draggable));
}
});
$(".stackDrop").droppable({
tolerance: "intersect",
accept: ".card",
activeClass: "ui-state-default",
hoverClass: "ui-state-hover",
drop: function(event, ui) {
$(this).append($(ui.draggable));
}
});
body {
margin: 0;
background-color: #ffffcc;
}
#launchPad {
width:170px;
float:left;
border: 1px solid #eaeaea;
background-color: #f5f5f5;
}
#dropZone {
float:right;
border: 1px solid #eaeaea;
background-color: #ffffcc;
}
.card {
width: 130px;
padding: 5px 10px;
margin:5px;
border:1px solid #ccc;
background-color: #eaeaea;
}
.stack {
display:inline-block;
vertical-align:top;
width: 180px;
border: 1px solid #ccc;
background-color: #f5f5f5;
margin: 20px;
}
.stackHdr {
background-color: #eaeaea;
border: 1px solid #fff;
padding: 5px
}
.stackDrop {
min-height:100px;
padding: 15px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
<div id="launchPad">
<div class="card draggable" >
apple
</div>
<div class="card draggable">
orange
</div>
<div class="card draggable">
banana
</div>
<div class="card draggable">
car
</div>
<div class="card draggable">
bus
</div>
</div>
<div id="dropZone">
<div class="stack">
<div class="stackHdr">
Drop here
</div>
<div class="stackDrop droppable">
</div>
</div>
<div class="stack">
<div class="stackHdr">
Or here
</div>
<div class="stackDrop droppable">
</div>
</div>
</div>
I am trying to create on hover color change of buttons using javascript code, the unclear part for me is how to set up 'this' attribute so the hovered element trigger the css part for specific button.
$('this').mouseover(function() {
$('#div').removeClass('svg-active');
$('#span').removeClass('light-blue-link');
});
$('this').mouseout(function() {
$('#div').removeClass('svg-active');
$('#span').removeClass('light-blue-link');
});
.button-outer {
margin-top: 30px;
}
.button {
height: 30px;
width: auto;
cursor: pointer;
z-index: 1;
}
.button::before {
display:inline-block;
content:'';
height: 100%;
vertical-align: middle;
}
.light-blue-link {
color: rgb(88, 202, 230);
}
span {
font-weight: 300;
transition: color 1s ease;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='button-outer'>
<div class='button'>
<div id='div' class='svg profile'></div>
<span id='span' class=''>Profile</span>
</div>
<div class='button'>
<div id='div' class='svg friends'></div>
<span id='span' class=''>Friends</span>
</div>
<div class='button'>
<div id='div' class='svg timeline'></div>
<span id='span' class=''>Timeline</span>
</div>
<div class='button'>
<div id='div' class='svg messages'></div>
<span id='span' class=''>Messages</span>
</div>
<div class='button'>
<div id='div' class='svg bookmarks'></div>
<span id='span' class=''>Bookmarks</span>
</div>
</div>
Note: First I address the JavaScript/jQuery question, but note the "However" bit at the end — you don't need them at all for this.
Instead of 'this' you want .button or div.button.
But that's not the main problem.
The main problem is that you're using the same id on more than one element. You can't do that, it's invalid, and browsers will typically use the first element and ignore the id on the other ones.
You don't need ids on those at all. Within your handlers, this will refer to the element you hooked the event on, so you can use the fact that the div and span are inside the element (via find) to find them:
$('div.button').mouseover(function() {
var $this = $(this);
$this.find('div').removeClass('svg-active');
$this.find('span').removeClass('light-blue-link');
});
$('div.button').mouseout(function() {
var $this = $(this);
$this.find('div').removeClass('svg-active');
$this.find('span').removeClass('light-blue-link');
});
Updated example:
$('div.button').mouseover(function() {
var $this = $(this);
$this.find('div').addClass('svg-active');
$this.find('span').addClass('light-blue-link');
});
$('div.button').mouseout(function() {
var $this = $(this);
$this.find('div').removeClass('svg-active');
$this.find('span').removeClass('light-blue-link');
});
.button-outer {
margin-top: 30px;
}
.button {
height: 30px;
width: auto;
cursor: pointer;
z-index: 1;
}
.button::before {
display: inline-block;
content: '';
height: 100%;
vertical-align: middle;
}
.light-blue-link {
color: rgb(88, 202, 230);
}
span {
font-weight: 300;
transition: color 1s ease;
}
<div class='button-outer'>
<div class='button'>
<div class='svg profile'></div>
<span class=''>Profile</span>
</div>
<div class='button'>
<div class='svg friends'></div>
<span class=''>Friends</span>
</div>
<div class='button'>
<div class='svg timeline'></div>
<span class=''>Timeline</span>
</div>
<div class='button'>
<div class='svg messages'></div>
<span class=''>Messages</span>
</div>
<div class='button'>
<div class='svg bookmarks'></div>
<span class=''>Bookmarks</span>
</div>
</div>
<!-- Scripts at the bottom unless you have a good reason to do something else -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I also changed the calls in your mouseover callback to addClass rather than removeClass.
Other things to consider:
You could use event delegation rather than hooking the event on the buttons directly:
$(".button-outer").on("mouseover", ".div.button", function() {
// ...
});
You could toggle a class on the button itself rather than on the things inside it, and then use structural CSS to apply the styling
However, you don't need JavaScript for this at all: Just use a div.button:hover div rule and a div.button:hover span rule:
.button-outer {
margin-top: 30px;
}
.button {
height: 30px;
width: auto;
cursor: pointer;
z-index: 1;
}
.button::before {
display: inline-block;
content: '';
height: 100%;
vertical-align: middle;
}
div.button:hover span {
color: rgb(88, 202, 230);
}
span {
font-weight: 300;
transition: color 1s ease;
}
<div class='button-outer'>
<div class='button'>
<div class='svg profile'></div>
<span class=''>Profile</span>
</div>
<div class='button'>
<div class='svg friends'></div>
<span class=''>Friends</span>
</div>
<div class='button'>
<div class='svg timeline'></div>
<span class=''>Timeline</span>
</div>
<div class='button'>
<div class='svg messages'></div>
<span class=''>Messages</span>
</div>
<div class='button'>
<div class='svg bookmarks'></div>
<span class=''>Bookmarks</span>
</div>
</div>
<!-- Scripts at the bottom unless you have a good reason to do something else -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
In jQuery, Argument as a string inside $() is a selector. It's failing due to jQuery method look out for element / tag in your DOM like below and One more below is invalid tag.
<this></this>
Try with valid selector like $('div.button')
Note: ID is for unique identifier. please use once. its not semantic if you use multiple times.
Efficient way will be from CSS. Main benefit will mouseout case will be taken care by browser.
div.button:hover {
color: blue;
font-size: 27px;
width:100px;
}
So I have 4 divs. I want to change the size of the inner divs compared to parent divs.
I want to dynamically change the child div size related to parent's one.
Now I've added .top class, but I don't really know if its needed or if it will be useful.
Here is the fiddle I'm testing with
http://jsfiddle.net/y3597/171/
jQuery below
$(".top").each(function () {
$('.object').width($(".inner").parent().width());
});
CSS below:
.container1 { width: 200px; background: red; padding: 2px; }
.container2 { width: 225px; background: purple; padding: 2px; }
.container3 { width: 250px; background: blue; padding: 2px; }
.container4 { width: 275px; background: black; padding: 2px; }
/* top ? */
.inner { width: 150px; background: gray; }
.object { width: 100px; background: green; }
HTML below:
<div class="container1 top">
<div class="inner">
<div class="object">Text 1</div>
</div>
<div class="container2 top">
<div class="inner">
<div class="object">Text 2</div>
</div>
<div class="container3 top">
<div class="inner">
<div class="object">Text 3</div>
</div>
<div class="container4 top">
<div class="inner">
<div class="object">Text 4</div>
</div>
I think that you are trying to achieve this:
$(".top").each(function () {
$(this).find(".object").width($(this).width());
});
In your code jQuery will check for every element with .object class in DOM on each loop. When you use (this) you are refering to element that is currently "selected" in loop.
Better way to achive this is to set widths od children to 100%, so they will inherit the witdhs from parents.