Working on a jQuery slide toggle where upon click of an item in a ul toggle down the corresponding item in another ul. I'm having trouble getting the click to be linked to the id and toggling the correct ul item.
jQuery is:
$(document).ready(function() {
//on click of subservices list item toggle down the corresponding subservices item
$(".subServices").find("li").hide().end() // Hide all other ULs
.click(function(e) {
if (this == e.target) { // if the handler element is where the event originated
$(this).children('ul.subServicesList.subServiceItem').slideToggle('fast');
}
});
});
Can anyone help :)
Fiddle here
First, ID of an element must be unique so you can't use same ID for subServices and SubServicesList. In the below solution we uses a data-target attribute for subServices.
Also you need to register the handler to .SubServicesList a element, not the SubServicesList
$(document).ready(function() {
//on click of subservices list item toggle down the corresponding subservices item
$(".subServices > li").hide().end() // Hide all other ULs
$('.SubServicesList a').click(function(e) {
$('#' + $(this).data('target')).slideToggle()
});
});
.SubServicesList {
display: block;
width: 55%;
text-align: center;
margin-left: auto;
margin-right: auto;
}
.SubServicesList li {
display: inline;
list-style: none;
list-style-type: none;
margin-right: 10px;
text-align: center;
line-height: 26px;
cursor: pointer;
}
.SubServicesList li a:hover {
color: #333333;
}
.subServices {
width: 75%;
margin: 0 auto;
}
.subServices li.subServiceItem {
display: block;
list-style: none;
list-style-type: none;
height: auto;
clear: both;
}
.subServices li.subServiceItem .image {
float: left;
display: block;
margin-right: 10px;
margin-bottom: 10px;
}
.subServices li.subServiceItem .image {
float: left;
display: block;
}
/*.subServices li.subServiceItem { display:none; } */
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<ul class="SubServicesList">
<li><a data-target="1">Name 1</a></li>
<li><a data-target="2">Name 2</a></li>
<li><a data-target="3">Name 3</a></li>
</ul>
<ul class="subServices">
<li class="subServiceItem" id="1">
1 hwiufhwriufhiurhfiureh
</li>
<li class="subServiceItem" id="2">
2 hwiufhwriufhiurhfiureh
</li>
<li class="subServiceItem" id="3">
3 hwiufhwriufhiurhfiureh
</li>
</ul>
This is how I did it
$(".SubServicesList > li > a").click(function () {
$(".subServices>li").hide();
$(".subServices").find("li[id='" + $(this).attr('id') + "']").slideToggle(true);
});
Here is the JSFiddle
Related
I'm not a developer. I've been however tasked with coming up with a solution for a small project at work with jQuery and I have no clue where to begin. Here's my codepen: https://codepen.io/axo1/pen/mdBLRjL
What I need to is this (all graphics and texts are placeholders):
What I managed to achieve
Image item1 is supposed to be the first visible,
Hovering on the buttons below the graphic changes which image is displayed,
What I don't know how to achieve
The buttons below should be clickable. Clicking on a button changes the "active" graphic above. For example: if I click on the Second item button, the item2 image will be displayed even after I unhover the button, and so forth.
Any tips of what I should look into?
Unfortunately jQuery is heavily preferred here.
$(document).on({
mouseenter: function() {
$(".item1").toggleClass("active hidden");
$(".item2").toggleClass("hidden");
},
mouseleave: function() {
$(".item1").toggleClass("active hidden");
$(".item2").toggleClass("hidden");
}
}, ".item2btn");
$(document).on({
mouseenter: function() {
$(".item1").toggleClass("active hidden");
$(".item3").toggleClass("hidden");
},
mouseleave: function() {
$(".item1").toggleClass("active hidden");
$(".item3").toggleClass("hidden");
}
}, ".item3btn");
img {
max-width: 15%;
position: absolute;
top: 0;
left: 0;
}
.hidden {
visibility: hidden;
}
.active {
visibility: visible;
}
#container {
display: flex;
justify-content: flex-start;
align-items: center;
color: white;
position: absolute;
top: 250px;
}
#container ul {
padding: 1em;
}
#container ul>li {
background: black;
margin: 1em;
padding: 1em;
list-style-type: none;
display: inline;
}
#container ul>li:hover {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<img src="https://www.models-resource.com/resources/big_icons/13/12406.png" class="active items item1">
<img src="https://banner2.cleanpng.com/20180410/rce/kisspng-the-legend-of-zelda-majora-s-mask-hyrule-warriors-the-legend-of-zelda-5acc7b7a4870f6.4303262815233503942967.jpg" class="hidden items item2">
<img src="https://i.pinimg.com/originals/4a/a5/df/4aa5df83115df6c96732a2d76ccb4f1b.jpg" class="hidden items item3">
<div id="container">
<ul>
<li class="item1btn">First item</li>
<li class="item2btn">Second item</li>
<li class="item3btn">Third item</li>
</ul>
</div>
Here is a working version
I kept your style - I think it can be shortened to be more DRY
const $images = $(".items")
let $currentItem = $(".items").eq(0)
$("#container li").on({
"click": function() {
const id = $(this).data("id").replace("btn", "");
$images
.removeClass("active")
.addClass("hidden")
$currentItem = $(`.${id}`)
.removeClass("hidden")
.addClass("active");
},
"mouseover": function() {
const id = $(this).data("id").replace("btn", "");
$images
.removeClass("active")
.addClass("hidden")
$(`.${id}`)
.removeClass("hidden")
.addClass("active");
},
"mouseout": function() {
$images
.removeClass("active")
.addClass("hidden")
$currentItem
.removeClass("hidden")
.addClass("active");
}
})
img {
max-width: 15%;
position: absolute;
top: 0;
left: 0;
}
.hidden {
visibility: hidden;
}
.active {
visibility: visible;
}
#container {
display: flex;
justify-content: flex-start;
align-items: center;
color: white;
position: absolute;
top: 250px;
}
#container ul {
padding: 1em;
}
#container ul>li {
background: black;
margin: 1em;
padding: 1em;
list-style-type: none;
display: inline;
}
#container ul>li:hover {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<img src="https://www.models-resource.com/resources/big_icons/13/12406.png" class="active items item1">
<img src="https://banner2.cleanpng.com/20180410/rce/kisspng-the-legend-of-zelda-majora-s-mask-hyrule-warriors-the-legend-of-zelda-5acc7b7a4870f6.4303262815233503942967.jpg" class="hidden items item2">
<img src="https://i.pinimg.com/originals/4a/a5/df/4aa5df83115df6c96732a2d76ccb4f1b.jpg" class="hidden items item3">
<div id="container">
<ul>
<li data-id="item1">First item</li>
<li data-id="item2">Second item</li>
<li data-id="item3">Third item</li>
</ul>
</div>
I created a simple navigation, but it doesn't work on mobile. When you click on the plus symbol or "Book 1 name" the list of links are suppose to appear, but for some reason it doesn't work, and when you click the plus symbol the ex symbol is suppose to appear. The book title should link should work on desktop, but not on mobile. Thanks!
$(document).ready(function () {
$(window).resize(function() {
if($(window).width() <= 550) {
$('.bookName').click(function(e){
e.preventDefault();
$('.bookNavigation ul li ul').toggleClass('toggleNav')
$(this).toggleClass('changeIcon');
});
} else {
$('.bookName').click(function(e){
return true;
});
}
});
});
.bookNavigation ul li ul{
display: flex;
}
.toggleNav{
display: block;
}
#media only screen and (max-width: 550px) {
.bookNavigation ul li ul{
display: none;
}
.bookName::before{
content: '+';
padding-right: 10px;
}
.bookName .changeIcon::before{
content: '-';
padding-right: 10px;
}
}
a{
text-decoration: none;
}
li{
list-style: none;
}
.bookNavigation{
margin-bottom: 100px;
}
.bookName{
text-transform: uppercase;
font-size: 30px;
}
li{
margin-right: 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav class="bookNavigation">
<ul>
<li>
Book 1 Name
<ul>
<li>Book 1 Chapter 1</li>
<li>Book 1 Chapter 2</li>
<li>Book 1 Chapter 3</li>
</ul>
</li>
</ul>
</nav>
<p>you are in Book 1 Name cover page</p>
You can do this check $(window).width() <= 550 inside the click event rather than attaching the event based on screen-size. Please find the corrected code.
$('.bookName').click(function(e) {
if ($(window).width() <= 550) {
e.preventDefault();
$('.bookNavigation ul li ul').toggleClass('toggleNav')
$(this).toggleClass('changeIcon');
}
});
.bookNavigation ul li ul {
display: flex;
}
.bookNavigation ul li ul.toggleNav {
display: block;
}
#media only screen and (max-width: 550px) {
.bookNavigation ul li ul {
display: none;
}
.bookName::before {
content: '+';
padding-right: 10px;
}
.bookName .changeIcon::before {
content: '-';
padding-right: 10px;
}
}
a {
text-decoration: none;
}
li {
list-style: none;
}
.bookNavigation {
margin-bottom: 100px;
}
.bookName {
text-transform: uppercase;
font-size: 30px;
}
li {
margin-right: 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav class="bookNavigation">
<ul>
<li>
Book 1 Name
<ul>
<li>Book 1 Chapter 1</li>
<li>Book 1 Chapter 2</li>
<li>Book 1 Chapter 3</li>
</ul>
</li>
</ul>
</nav>
<p>you are in Book 1 Name cover page</p>
Instead of checking on resize, check the window with inside buttonClickHandler like below
$(button).on('click', function(){
if($(window).width() <= 550){
// Code to toggle list
}
});
Another problem was the specificity of toggleNav css class.
.bookNavigation ul li ul {
display: none;
}
Above code is more specific than
.toggleNav {
display: block;
}
So the toggling toggleNav won't work because the 1st one will override this one. For fixing it create a class like the one below and toggle it on click. So that it will be hidden initially and will be removed on click.
.navHidden {
display: none
}
Check this pin for working example: https://codesandbox.io/s/bold-currying-39w11
So I'm trying to create an accordion style menu where if you click a panel it opens the section. If you click it again, it closes. On top of that, it should also close any other panel that was previously opened.
I've almost got that functionality but the problem is that I have to click it twice.
To see what I mean, check out this Fiddle
You'll notice that if you open link one then try to open link 2, you'll have to press link 2 twice.
How can I make it so that you only have to press it once to close link 1 but also open link 2 ?
let dropdown = document.querySelectorAll('.dropdown-toggle');
const handleClick = (e) => {
const active = document.querySelector('.open');
if(active){
active.classList.remove('open');
} else {
e.currentTarget.nextElementSibling.classList.add('open')
}
}
dropdown.forEach(element => {
element.addEventListener('click', handleClick);
});
body {
background: #ccc;
}
.menu {
background: #fff;
margin: 0 auto;
max-width: 400px;
}
.menu ul {
padding: 0;
text-align: center;
width: 100%;
}
.menu ul li {
list-style: none;
padding: 20px 0;
border-bottom: 1px solid #ccc;
}
.menu ul li a {
text-decoration: none;
}
.menu ul li .dropdown {
display: none;
padding: 20px;
background: grey;
}
.menu ul li .dropdown.open {
display: block;
}
<div class="menu">
<ul>
<li>
link 1
<div class="dropdown">Some text</div>
</li>
<li>
link 2
<div class="dropdown">Some text</div>
</li>
<li>
link 3
<div class="dropdown">Some text</div>
</li>
<li>
link 4
<div class="dropdown">Some text</div>
</li>
<li>
link 5
<div class="dropdown">Some text</div>
</li>
</ul>
</div>
Can use js like the following.
let dropdown = document.querySelectorAll('.dropdown-toggle');
const handleClick = (e) => {
const isLastOpenTargetClicked = e.currentTarget.nextElementSibling.classList.contains('open');
if(isLastOpenTargetClicked) {
e.currentTarget.nextElementSibling.classList.remove('open');
return;
}
const active = document.querySelector('.open');
if(active){
active.classList.remove('open');
}
e.currentTarget.nextElementSibling.classList.add('open')
}
dropdown.forEach(element => {
element.addEventListener('click', handleClick);
});
body {
background: #ccc;
}
.menu {
background: #fff;
margin: 0 auto;
max-width: 400px;
}
.menu ul {
padding: 0;
text-align: center;
width: 100%;
}
.menu ul li {
list-style: none;
padding: 20px 0;
border-bottom: 1px solid #ccc;
}
.menu ul li a {
text-decoration: none;
}
.menu ul li .dropdown {
display: none;
padding: 20px;
background: grey;
}
.menu ul li .dropdown.open {
display: block;
}
<div class="menu">
<ul>
<li>
link 1
<div class="dropdown">Some text</div>
</li>
<li>
link 2
<div class="dropdown">Some text</div>
</li>
<li>
link 3
<div class="dropdown">Some text</div>
</li>
<li>
link 4
<div class="dropdown">Some text</div>
</li>
<li>
link 5
<div class="dropdown">Some text</div>
</li>
</ul>
</div>
There's no need to check whether the current element is active; On the click handler you simply want to check whether the .nextElementSibling's .classList contains the class open. If it does, remove it. If it doesn't, apply it.
This can be seen in the following:
let dropdown = document.querySelectorAll('.dropdown-toggle');
const handleClick = (e) => {
if (e.currentTarget.nextElementSibling.classList.contains('open')) {
e.currentTarget.nextElementSibling.classList.remove('open');
} else {
e.currentTarget.nextElementSibling.classList.add('open')
}
}
dropdown.forEach(element => {
element.addEventListener('click', handleClick);
});
body {
background: #ccc;
}
.menu {
background: #fff;
margin: 0 auto;
max-width: 400px;
}
.menu ul {
padding: 0;
text-align: center;
width: 100%;
}
.menu ul li {
list-style: none;
padding: 20px 0;
border-bottom: 1px solid #ccc;
}
.menu ul li a {
text-decoration: none;
}
.menu ul li .dropdown {
display: none;
padding: 20px;
background: grey;
}
.menu ul li .dropdown.open {
display: block;
}
<div class="menu">
<ul>
<li>
link 1
<div class="dropdown">Some text</div>
</li>
<li>
link 2
<div class="dropdown">Some text</div>
</li>
<li>
link 3
<div class="dropdown">Some text</div>
</li>
<li>
link 4
<div class="dropdown">Some text</div>
</li>
<li>
link 5
<div class="dropdown">Some text</div>
</li>
</ul>
</div>
Inside your click handler, loop the document.querySelectorAll('.dropdown-toggle'), remove all the open from classlist, then add open to the current target
Problem description:
In my menu when .mouseenter() the menu opens and when .mouseleave() it closes, but if i click a lot , the .mouseleave() event is executed.
This only happened on chrome browser.
I have other .click() events inside my menu, but every click I made, the .mouseleave() event is execute.
$(document).ready(function() {
$("#nav1 li").hover(
function() {
$(this).find('ul').slideDown();
},
function() {
$(this).find('ul').slideUp();
});
});
#nav1 a {
color: #FFFFFF;
}
#nav1 li ul li a:hover {
background-color: #394963;
}
div ul li ul {
background-color: #4a5b78;
list-style: none
}
#nav1 > li > a {
padding: 16px 18px;
display: block;
border-bottom: 2px solid #212121;
}
#nav1 li ul li a {
padding: 10px 0;
}
div {
background-color: #000000;
background-color: #343434;
width: 280px;
}
/* Hide Dropdowns by Default */
#nav1 li ul {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<ul id="nav1">
<li>Hover here and infinite click
<ul>
<li>Stage1</li>
<li>Stage2</li>
<li>Stage3</li>
<li>Stage4</li>
</ul>
</li>
<li>Menu Heading 2
<ul>
<li>Stage1</li>
<li>Stage2</li>
<li>Stage3</li>
<li>Stage4</li>
</ul>
</li>
</ul>
<div>
Try click "Hover here and infinite click" to see this problem.
EDIT:
As you guys said, the problem occurs in this example.
Here is a video: Video link
When you click many times the browser has lost the element reference, try this example:
<div id="container">
<ul id="nav1">
<li>Menu Heading 1
<ul>
<li>Stage1</li>
<li>Stage2</li>
<li>Stage3</li>
<li>Stage4</li>
</ul>
</li>
<li>Menu Heading 2
<ul>
<li>Stage1</li>
<li>Stage2</li>
<li>Stage3</li>
<li>Stage4</li>
</ul>
</li>
<li>Menu Heading 3
<ul>
<li>Stage1</li>
<li>Stage2</li>
<li>Stage3</li>
<li>Stage4</li>
</ul>
</li>
</ul>
<div>
Css
ul,
li,
a {
padding: 0px;
margin: 0px;
}
.show {
display: block !important;
}
#nav1 a {
color: #FFFFFF;
}
#nav1 li ul li a:hover {
background-color: #394963;
}
div ul li ul {
background-color: #4a5b78;
list-style: none
}
#nav1 > li > a {
background-color: #343434;
padding: 16px 18px;
text-decoration: none;
display: block;
border-bottom: 2px solid #212121;
background: linear-gradient(top, #343434, #111111);
}
#nav1 li ul li a {
padding: 10px 0;
padding-left: 30px;
text-decoration: none;
display: block;
}
div {
background-color: #000000;
background-color: #343434;
width: 280px;
}
/* Hide Dropdowns by Default */
#nav1 li ul {
display: none;
}
JS
$(document).ready(function() {
$("#nav1 li").hover(
function(e) {
let ulMenu = $(this).find('ul');
ulMenu.addClass('show');
//$(this).find('ul').slideDown();
},
function(e) {
if(e.relatedTarget){
let ulMenu = $(this).find('ul');
ulMenu.removeClass('show');
} else {
console.log('fail ');
}
//$(this).find('ul').slideUp();
});
});
Codepen Example Works
You can add a stropPropagation in your click event.
$("#nav1 li").click(
function(e){
e.stopPropagation();
});
maybe the event is getting lost in the process, try to verify it, and if so set the actual element.
see this: https://api.jquery.com/event.relatedTarget/
Is there a way through JavaScript to set the links on a timer before its closes out? I don't want it to seem so sensitive. Such as if a user accidentally mouses off the link it closes right away. Any video recommendation or links?
Thanks,
I am not using jQuery......
* {
padding: 0;
margin: 0;
}
body {
padding: 5px;
font-family: Cambria, "Hoefler Text", "Liberation Serif", Times, "Times New Roman", serif;
}
ul {
list-style: none;
}
ul li {
float: left;
padding-right: 1px;
position: relative;
}
ul a {
display: table-cell;
vertical-align: middle;
width: 100px;
height: 50px;
text-align: center;
background-color: #2F2F2F;
color: #AE0002;
text-decoration: none;
}
ul a:hover {
background-color: #828282;
color: #FFFFFF;
}
li > ul {
display: none;
position: absolute;
left: 0;
top: 100%;
}
li:hover > ul {
display: block;
}
li > ul li {
padding: 0px;
padding-top: 1px;
}
li > ul li > ul {
left: 100%;
top: 0;
padding-left: 1px;
}
li > ul li > ul li {
width: 100px;
}
<body>
<ul>
<li>Sports News
<ul>
<li>Football
<ul>
<li>NFL
</li>
<li>ESPN Football
</li>
</ul>
</li>
<li>Baseball
<ul>
<li>MLB
</li>
<li>ESPN Baseball
</li>
</ul>
</li>
<li>Soccer
<ul>
<li>FIFA
</li>
<li>ESPN Soccer
</li>
</ul>
</li>
<li>Basketball
<ul>
<li>NBA
</li>
<li>ESPN Basketball
</li>
</ul>
</li>
<li>Auto Racing
<ul>
<li>ESPN Racing
</li>
<li>Nascar
</li>
</ul>
</li>
</ul>
</li>
</ul>
</body>
Instead of css, show/hide ul using javascript. Handle mouseover and mouseout events to show/hide. To delay, on hover, show using timer and on mouseout, hide as well as clear the timer.
function show(ul) {
ul.css("display", "inline-block");
}
function hide(ul) {
ul.css("display", "none");
}
$("li").mouseover(function () {
var ul = $(this).children("ul");
var timer = setTimeout(function () {
show(ul);
}, 400);
$(this).data("timer", timer);
}).mouseout(function () {
var ul = $(this).children("ul");
var timer = $(this).data("timer");
clearTimeout(timer);
hide(ul);
});
Demo: http://jsfiddle.net/k06dLnmk/
You can use transition delay.
transition-delay:1s;
Similar Question:
Delay hover
or you can use javascript to toggle with the css clasess
window.setInterval("javascript function", milliseconds);
Edit: Oh sorry as the comment pointed out. display none does not work with transition delay. Would you consider using visibility property instead?
div > ul {
. . .
visibility:hidden;
opacity:0;
transition:visibility 0s linear 0.5s,opacity 0.5s linear;
}
div:hover > ul {
visibility:visible;
opacity:1;
transition-delay:0s;
}