I have a menu with a list of items created dynamically using javascript.
They have different colour and country attributes created using setAttribute.
$("#menuList a").hover(
function() {
var countryName = $(this).attr('country');
var fruitColour = $(this).attr('colour');
$('#toshow').append($("countryName \n fruitColour"));
},
function() {}
);
.toshow {
display: none;
}
#menuList a:hover div.toshow {
top: 0;
right: 0;
display: block;
position: absolute;
z-index: 99999;
background: red;
width: 200px;
height: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="menubar" id="menuList">
<li>Watermelon</li>
<li>Grapes</li>
<li>Strawberry</li>
<li>Blueberry</li>
</ul>
<div class="toshow" id="toshow"></div>
Here, I want to have a separated hidden div (display at top right of the page or next to the menuList) that does not have any content until any of the <a> tag being hovered, and show its responding two attributes until no more mouse hovered.
The code does not have errors. But I don't see anything in red when the mouse hovered through the list. Is it possible to achieve what I am looking for?
You can use the mouseout event to hide the toshow div with hide as you leave a list element. And at each hover event, you can change the html of toshow to the values of the li element which the user is hovering over and use show to display it.
Also make sure you attach the event handlers after you've inserted the html of the dynamically generated list.:
function displayGeneratedList() {
$('#menuList').html(`
<li>Watermelon</li>
<li>Grapes</li>
<li>Strawberry</li>
<li>Blueberry</li>
`);
$("#menuList a").hover(function() {
var countryName = $(this).attr('country');
var fruitColour = $(this).attr('colour');
$('#toshow').html(`${countryName}<br>${fruitColour}`).show();
});
$('#menuList a').mouseout(function() {
$('#toshow').hide();
});
}
$(document).ready(function() {
displayGeneratedList();
});
#menuList {
display: inline-block;
}
.toshow {
display: none;
float: right;
background: maroon;
width: 200px;
height: 100px;
padding: 5px;
color: white
}
<ul class="menubar" id="menuList">
</ul>
<div class="toshow" id="toshow"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Related
I'm relatively new to jQuery, and I'm experiencing some trouble with it. My assignment is to redesign a webpage and implement certain features using jQuery. Right now, I'm trying to create a dropdown menu for each "button" in my nav bar. When I hover over a "button" in the nav bar, a dropdown menu should show up. My jQuery appears to be working but the dropdown menu isn't showing up on the webpage...
Here is my code:
<head>
<title>Team Imperial College: Project Description</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="js/main.js"></script>
<link rel="stylesheet" href="styles/normalize.css" type="text/css"/>
<link rel="stylesheet" href="styles/styles.css" type="text/css"/>
</head>
Here is the HTML code (nav bar and dropdown menu code):
<ul class="nav_bar">
<li class="dropdown">
Our Team
<ul class="dropdown_content">
<li>Meet the Team</li>
<li>Attributes</li>
</ul>
</li>
<li>Our Project</li>
<li>
Modelling
</li>
<li>Software</li>
<li>
Documentation
</li>
<li>
Human Centered Design
</li>
</ul>
Here is my CSS code:
html, body {
margin: 0;
padding: 0;
font-family: 'Raleway', sans-serif;
background-color: #EDDBDB;
}
.nav_bar {
position: fixed;
top: 0px;
width: 100%;
list-style-type: none;
margin: 0;
padding: 0;
background-color: #F3F3FF;
overflow: hidden;
}
.nav_bar li {
float: left;
}
li a {
display: block;
color: #000000;
text-align: center;
padding: 24px 20px;
text-decoration: none;
font-size: 105%;
}
/*dropdown menu code*/
.dropdown {
position: relative;
display: inline-block;
}
.dropdown_content {
display: none;
position: absolute;
background-color: #F3F3FF;
min-width: 160px;
z-index: 1;
}
.dropdown_content li a {
color: #000000;
padding: 12px 16px;
text-decoration: none;
display: block;
}
.dropdown_content li a:hover {
background-color: #DBDBE5;
}
.dropdown:hover .dropdown_content {
display: block;
}
/dropdown menu code/
And here is my jQuery code:
$(document).ready(function() {
$('.dropdown').hover(function() {
$('.dropdown_content').toggle();
});
$('.dropdown_content li a').hover();
});
Please help! Help will be greatly appreciated, thanks!
First test i would make is make dropdown_content visible since begin, to make sure the toggle function works.
Then you can do this test:
$('.dropdown').hover(function() {
$('.dropdown_content').toggle();
alert('Over here');
});
Check how many times "Over here" appears.
Having those answers will help you on the way out of this.
if (jQuery) {
alert(“jquery is loaded”);
} else {
alert(” Not loaded”);
}
it seems you haven't addressed the event on mouse out. try changing this code:
$('.dropdown').hover(function() {
$('.dropdown_content').toggle();
});
to this:
$('.dropdown').hover(function() {
$('.dropdown_content').toggle();
}, function() {
$('.dropdown_content').toggle();
});
if you want it only to be trigger on when entering it do this:
$('.dropdown').mouseenter(function() {
$('.dropdown_content').toggle();
});
i suggest looking at this for better detail.
EDIT:
how toggle works is by making the element's display variable to none that essentially means that it does not exist on the page anymore.
if you wanted it to toggle on hover, you would need to toggle the opacity between 0 and 1.
best method:
create a css class
.hidden {
opacity: 0;
}
edit JQuery code
$(document).ready(function() {
$('.dropdown').hover(function() {
$('.dropdown').toggleClass('.dropdown', "hidden");
//you can use this for multiple elements
//$(this).toggleClass(this, "hidden");
});
$('.dropdown_content li a').hover();
});
deprecated method:
$(document).ready(function() {
$('.dropdown').hover(function() {
$('.dropdown_content').toggle(() => {
$('.dropdown_content').css({opacity: "0"});
}, () => {
$('.dropdown_content').css({opacity: "1"});
});
});
$('.dropdown_content li a').hover();
});
note: () => {} is shorthand for a callback function
Below is a simplified version of the input dropdown I am working with.
A basic summary of what it does is: if you focus on the input, a dropdown appears. If you click one of the options in the dropdown, the option populates the input and the dropdown disappears. This is achieved using onfocus and a functions I called dropdown(); and undropdown();.
I'm in a dilemma, where I'm unable to make the dropdown disappear when someone clicks elsewhere. If I use onblur, it successfully hides the dropdown, but if you click on an option it doesn't populate the input, this is because, the onblur function runs first and, therefore, the input(); function doesn't not run because the dropdown is already hidden.
If you put an onclick on the body tag, or other parent, it considers the onfocus as a click, where it run's the dropdown(); function then the undropdown(); function immediately so the dropdown never appears since the functions overlap.
I would appreciate help on figuring out how to order the functions so that they are executed in the right order without overlapping with each other.
JSFiddle available here.
function input(pos) {
var dropdown = document.getElementsByClassName('drop');
var li = dropdown[0].getElementsByTagName("li");
document.getElementsByTagName('input')[0].value = li[pos].innerHTML;
undropdown(0);
}
function dropdown(pos) {
document.getElementsByClassName('content')[pos].style.display = "block"
}
function undropdown(pos) {
document.getElementsByClassName('content')[pos].style.display = "none";
}
.drop {
position: relative;
display: inline-block;
vertical-align: top;
overflow: visible;
}
.content {
display: none;
list-style-type: none;
border: 1px solid #000;
padding: 0;
margin: 0;
position: absolute;
z-index: 2;
width: 100%;
max-height: 190px;
overflow-y: scroll;
}
.content li {
padding: 12px 16px;
display: block;
margin: 0;
}
<div class="drop">
<input type="text" name="class" placeholder="Class" onfocus="dropdown(0)"/>
<ul class="content">
<li onclick="input(0)">Option 1</li>
<li onclick="input(1)">Option 2</li>
<li onclick="input(2)">Option 3</li>
<li onclick="input(3)">Option 4</li>
</ul>
</div>
PS: In addition to the above problem, I would appreciate suggestion for edits to get a better title for this question such that someone experiencing a similar problem could find it more easily.
In this case, On onblur you could call a function which fires the undropdown(0); after a very tiny setTimeout almost instantly. Like so:
function set() {
setTimeout(function(){
undropdown(0);
}, 100);
}
HTML
<input type="text" name="class" placeholder="Class" onfocus="dropdown(0)" onblur="set()" />
No other change is required.
function input(pos) {
var dropdown = document.getElementsByClassName('drop');
var li = dropdown[0].getElementsByTagName("li");
document.getElementsByTagName('input')[0].value = li[pos].innerHTML;
undropdown(0);
}
function dropdown(pos) {
document.getElementsByClassName('content')[pos].style.display= "block"
}
function undropdown(pos) {
document.getElementsByClassName('content')[pos].style.display= "none";
}
function set() {
setTimeout(function(){
undropdown(0);
}, 100);
}
.drop {
position: relative;
display: inline-block;
vertical-align:top;
overflow: visible;
}
.content {
display: none;
list-style-type: none;
border: 1px solid #000;
padding: 0;
margin: 0;
position: absolute;
z-index: 2;
width: 100%;
max-height: 190px;
overflow-y: scroll;
}
.content li {
padding: 12px 16px;
display: block;
margin: 0;
}
<div class="drop">
<input type="text" name="class" placeholder="Class" onfocus="dropdown(0)" onblur="set()" />
<ul class="content">
<li onclick="input(0)">Option 1</li>
<li onclick="input(1)">Option 2</li>
<li onclick="input(2)">Option 3</li>
<li onclick="input(3)">Option 4</li>
</ul>
</div>
You could make the dropdown focusable with tabindex, and in the input's blur event listener only hide the dropdown if the focus didn't go to the dropdown (see When onblur occurs, how can I find out which element focus went to?)
<ul class="content" tabindex="-1"></ul>
input.addEventListener('blur', function(e) {
if(!e.relatedTarget || !e.relatedTarget.classList.contains('content')) {
undropdown(0);
}
});
function input(e) {
var dropdown = document.getElementsByClassName('drop');
var li = dropdown[0].getElementsByTagName("li");
document.getElementsByTagName('input')[0].value = e.target.textContent;
undropdown(0);
}
[].forEach.call(document.getElementsByTagName('li'), function(el) {
el.addEventListener('click', input);
});
function dropdown(pos) {
document.getElementsByClassName('content')[pos].style.display = "block"
}
function undropdown(pos) {
document.getElementsByClassName('content')[pos].style.display = "none";
}
var input = document.getElementsByTagName('input')[0];
input.addEventListener('focus', function(e) {
dropdown(0);
});
input.addEventListener('blur', function(e) {
if(!e.relatedTarget || !e.relatedTarget.classList.contains('content')) {
undropdown(0);
}
});
.drop {
position: relative;
display: inline-block;
vertical-align: top;
overflow: visible;
}
.content {
display: none;
list-style-type: none;
border: 1px solid #000;
padding: 0;
margin: 0;
position: absolute;
z-index: 2;
width: 100%;
max-height: 190px;
overflow-y: scroll;
outline: none;
}
.content li {
padding: 12px 16px;
display: block;
margin: 0;
}
<div class="drop">
<input type="text" name="class" placeholder="Class" />
<ul class="content" tabindex="-1">
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
<li>Option 4</li>
</ul>
</div>
Accepted answer is a naive and unreliable approach. I had a hard-to-catch bug in a complex application because I used a setTimeout to give ~200ms delay so the browser can process dropdown click before blur event happens. While it worked great on every setup I tested it with, some users did have issues, in particular users with slower machines.
The correct way is to test relatedTarget on focusout event:
input.addEventListener('focusout', function(event) {
if(!isDropdownElement(event.relatedTarget)) {
// hide dropdown
}
});
relatedTarget for focusout contains an element reference, which is receiving focus. This reliably works in every browser I've tested so far (I didn't test IE10 and lower, only IE11 and Edge).
W3Schools has a nice example of how to create a custom dropdown:
https://www.w3schools.com/howto/howto_custom_select.asp
This is how the focus is handled in that example:
A global click-handler handles clicks outside of the dropdown list: document.addEventListener("click", closeAllSelect);. So as soon as the user clicks anywhere in the document, all dropdowns are closed.
But when the user selects an element of the dropdown list, the click-event is stopped by e.stopPropagation(); inside of the selection-handler.
This way, you don´t need the timer workaround.
i have created a dropdown menu which opens on clicking the nav button. But i couldn't find a way to close the dropdown menu when the mouse clicks on the body of the page.
I you can figure it out, please help me
(function(){
var bodyEl = $('body'),
navToggleBtn= bodyEl.find('.nav-toggle-btn');
navToggleBtn.on('click', function(e){
bodyEl.toggleClass('active-nav');
e.preventDefault();
});
})();
active-nav is created within css and linked with menu and body
You can bind click event to body, then check if the event is generated from a particular element using event.target
var bodyEl = $('body');
navToggleBtn = bodyEl.find('.nav-toggle-btn');
$('body').on('click', function (e) {
if ($(e.target).hasClass("nav-toggle-btn")) {
bodyEl.toggleClass('active-nav');
e.preventDefault();
e.stopPropagation();
}
else
{
//close the menu here
}
});
I don't know if it is the right solution, but I would add a div element that covers the entire page.
The menu is on top of that div, but the rest is below. If you click the div, it closes itself and the menu.
So basically, it's a lightbox (as for showing images), but without the shade. Or width a shade, because it will make your menu stand out a little more, and it will fit the expectations of disabling clicks on specific elements in the body.
Another advantage of having an extra element instead of just capturing clicks on the main level on the body, it that it won't interfere with other event handlers on the body itself, which could capture the click and therefor have unexpected results for someone who just wants to close the menu.
A rough example can be found below:
$('header > ul > li').on('click', function() {
// Deactive all menu items
$('ul.active').removeClass('active');
// Activate the one clicked.
$(this).closest('li').addClass('active');
// If there is no lightbox setup a new one.
var box = $('.lightbox');
if (box.length == 0) {
// It's just a div with a class.
$('<div>')
.prependTo($('body'))
.addClass('lightbox')
.on('click', function() {
// Lightbox clicked? Remove it, and deactivate the menu.
$('.lightbox').remove();
$('li.active').removeClass('active');
});
}
});
li {
padding: 1em;
}
header > ul > li {
display: inline-block;
vertical-align: top;
position: relative;
background-color: #eee;
}
li > ul {
display: none;
background-color: #ddd;
position: absolute;
top: 100%;
left: 0;
}
li.active > ul {
display: block;
}
.lightbox {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: rgba(0,0,0, 0.2); /* Just for show */
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header>
Header, page title
<ul>
<li>Main
<ul>
<li>sub</li>
<li>sub</li>
<li>sub</li>
<li>sub</li>
</ul>
</li>
<li>Other</li>
<li>About</li>
</ul>
</header>
<section>
Main content
</section>
I am trying to make a show content on mouseover and make it stay visible while the mouse is hovered on the list since I am planning to put a button there, but when I do hover, hidden content kept bouncing for some reason.
jQuery code
$('li.employers').mouseover(function () {
$('.employer_content').show("slow");
$(this).addClass("bluehover");
});
$('li.employers').mouseout(function () {
$('.employer_content').hide("fast");
$(this).removeClass("bluehover");
});
HTML
<li class="employers">
<div>employer</div>
<div class="employer_content">some content.</div>
</li>
<li class="court">
<div>court</div>
<div class="court_content">some content.</div>
</li>
http://jsfiddle.net/zLdnnxnh/3/
You can use only CSS to show/hide the contents.
You can take advantage of :hover class in CSS.
Demo using CSS only
.whatwedo {
padding: 20px;
color: #fff;
max-width: 480px;
margin: 0 auto;
}
ul li {
list-style-type: none;
}
ul > li {
background-color: #08588c;
display: inline-block;
width: 100%;
cursor: pointer;
float: left;
max-width: 100px;
padding: 10px;
}
.whatwedo {} ul.wwd_list {
padding: 0;
margin: 0;
}
.employer_content,
.court_content,
.companies_content,
.labor_content {
display: none;
clear: right;
}
.bluehover {
background-color: #01395d;
}
.content {
padding-top: 10px;
display: none;
}
.wwd_list li:hover .content {
display: block;
}
<div class="whatwedo">
<ul class="wwd_list">
<li class="employers">
<div>employer</div>
<div class="content">some content.</div>
</li>
<li class="court">
<div>court</div>
<div class="content">some content.</div>
</li>
<li class="companies">
<div>companies</div>
<div class="content">some content.</div>
</li>
<li class="laborunion">
<div>labour union</div>
<div class="content">some content.</div>
</li>
</ul>
</div>
CSS Demo with Animation
If you still want to use jQuery:
You are using mouseover event that is causing the handler to run when the mouse is moved over the element, use mousein instead
Use hover instead of mousein and mouseout
Your code is not flexible, you can optimize your code as follow
Use stop() to stop the previous animations
Demo
$('.wwd_list li').hover(function() {
$(this).find('div.content').stop().show("slow");
$(this).addClass("bluehover");
}, function() {
$(this).find('div.content').stop().hide("slow");
$(this).removeClass("bluehover");
});
.whatwedo {
padding: 20px;
color: #fff;
max-width: 480px;
margin: 0 auto;
}
ul li {
list-style-type: none;
}
ul > li {
background-color: #08588c;
display: inline-block;
width: 100%;
cursor: pointer;
float: left;
max-width: 100px;
padding: 10px;
}
.whatwedo {} ul.wwd_list {
padding: 0;
margin: 0;
}
.employer_content,
.court_content,
.companies_content,
.labor_content {
display: none;
clear: right;
}
.bluehover {
background-color: #01395d;
}
.content {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<div class="whatwedo">
<ul class="wwd_list">
<li class="employers">
<div>employer</div>
<div class="content">some content.</div>
</li>
<li class="court">
<div>court</div>
<div class="content">some content.</div>
</li>
<li class="companies">
<div>companies</div>
<div class="content">some content.</div>
</li>
<li class="laborunion">
<div>labour union</div>
<div class="content">some content.</div>
</li>
</ul>
</div>
You can use hover instead of mouseover and mouseout. Something like this:
$('li.employers').hover(function () {
$('.employer_content').show("slow");
$(this).addClass( "bluehover" );
console.log('mouse in');
}, function() {
$('.employer_content').hide("slow");
$(this).removeClass( "bluehover" );
console.log('mouse out');
});
Here's an example
How about this?
You can use stop() to stop the animation and continue the new animation from where it has stopped
$('.employer_content').stop().show("slow");
$('.employer_content').stop().hide("slow");
As recommended by others, use mouseenter than mouseover
Replace mouseover function with mouseenter and mouseout with mouseleave.
You can see this fiddle is working.
http://jsfiddle.net/ebilgin/zLdnnxnh/7/
Try using mouseenter and mouseleave instead:
From https://api.jquery.com/mouseover/:
This event type can cause many headaches due to event bubbling. For
instance, when the mouse pointer moves over the Inner element in this
example, a mouseover event will be sent to that, then trickle up to
Outer. This can trigger our bound mouseover handler at inopportune
times. See the discussion for .mouseenter() for a useful alternative.
$('li.employers').mouseenter(function () {
$('.employer_content').show("slow");
$(this).addClass("bluehover");
});
$('li.employers').mouseleave(function () {
$('.employer_content').hide("fast");
$(this).removeClass("bluehover");
});
http://jsfiddle.net/zLdnnxnh/5/
Just remove fast from your hide function. It is WORKING. Check this fiddle: http://jsfiddle.net/zp3jr43u/
The JavaScript code should like the following.
$('li.employers').mouseover(function () {
$('.employer_content').show("slow");
$(this).addClass("bluehover");
});
$('li.employers').mouseout(function () {
$('.employer_content').hide();
$(this).removeClass("bluehover");
});
Somehow the mouseover event gets triggered multiple times. I got it working by using the .stop() method before toggling the element.
http://jsfiddle.net/zLdnnxnh/4/
There's no need to have separate classes for each list item you have. Even with these separate classes the code below should get you up and running with ease.
$('.wwd_list li').hover(function () {
$('div:last-child',this).show("slow");
$(this).addClass( "bluehover" );
}, function(){
$('div:last-child',this).hide("slow");
$(this).removeClass( "bluehover" );
});
Note the fact that you only need to use one hover function instead of mouse in and mouse out. This works because you have two divs in the wwd_lsit class and the last one just so happens to be the one you want to target. So be careful with this if you ever want to change something!
Replace mouseover with mouseenter and mouseout with mouseleave.
See a more factorised form :
$('li').on({
mouseenter: function() {
jQuery("div.content", this).show('slow');
$(this).addClass( "bluehover" );
},
mouseleave: function() {
jQuery("div.content", this).hide('fast');
$(this).removeClass( "bluehover" );
}
});
(content class has been added to each content divs)
See the updated fiddle
There are 3 divs and 3 links.
Only one div should be displayed at a time. When user clicks on a link for one of the other divs, the current one should fade out and the selected one should fade in, in place of the previous div.
Here is the code at the moment:
Javascript
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function() {
switches = $('#switches > li');
slides = $('#slides > div');
switches.each(function(idx) {
$(this).data('slide', slides.eq(idx));
}).click(
function() {
switches.removeClass('active');
slides.removeClass('active').fadeOut('slow');
$(this).addClass('active');
$(this).data('slide').addClass('active').fadeIn('slow');
});
});
</script>
CSS
<style style="text/css">
ul {
list-style: none;
}
li:hover {
text-decoration: underline;
}
#switches .active {
font-weight: bold;
}
#slides div {
display: none;
}
#slides div.active {
display: block;
}
.outer {
position: absolute;
}
.outer div {
width: 600px;
height: 300px;
}
#uno {
background-color: red;
}
#dos {
background-color: blue;
}
#tres {
background-color: green;
}
</style>
HTML
<ul id="switches">
<li class="active">First slide</li>
<li>Second slide</li>
<li>Third slide</li>
</ul>
<div class="outer" id="slides">
<div class="active" id="uno">
First div.
</div>
<div id="dos">
Second div.
</div>
<div id="tres">
Third div.
</div>
</div>
You can view the page here:
http://dl.dropbox.com/u/6920023/proofOfConcept.html
I'm attempting to use standard Jquery to do this, but clearly there is something wrong with my javascript code.
Can you spot what's wrong and how to fix it?
Your CSS defines a div that's not active as hidden. So as soon as you remove the active class, it will be hidden immediately.
So, remove this entry:
#slides div {
display: none;
}
And add something like this on page load:
$(function() {
$('#slides div:not([class="active"])').hide();
}); // will hide inactive slides initially but not always
The issue is that you use slides.removeClass('active').fadeOut('slow');. So first it will remove the active class, which means (according to your CSS) that it will be a regular div, thus with the property display: none;.
So your div is automatically hidden. It's only afterwards that you do your fadeOut('slow'), on a hidden div thus.
Better would be to do something like:
$('div.active').fadeOut(1000).delay(1000).removeClass('active');
$(this).delay(2000).fadeIn(1000).delay(1000).addClass('active');
This works, if I understand the question correctly.
The issue is that you can't fade in an element that is hot hidden or unchcanged.
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function() {
switches = $('#switches > li');
slides = $('#slides > div');
switches.each(function(idx) {
$(this).data('slide', slides.eq(idx));
}).click(
function() {
switches.removeClass('active');
slides.removeClass('active').fadeOut('slow').hide();
$(this).addClass('active');
$(this).data('slide').addClass('active').fadeIn('slow');
});
});
</script>