I'm trying to be able to toggle these sub menus one at a time, I'm getting lost in nests and cant quite figure out how to target the correct list item,
I found that I should be using find() instead of children() as it can go deeper in the nest but still no luck in getting it working.
<ul>
<li>Profile</li>
<li>Edit</li>
<li class="drop-nav"> See your products
<ul>
<li class="drop-nav"> Mens
<ul>
<li> jumpers </li>
<li> t shirts </li>
</ul>
</li>
<li class="drop-nav"> Womens
<ul>
<li> hoodies </li>
<li> leggings </li>
</ul>
</li>
</ul>
</li>
</ul>
$(".drop-nav").on("click", function(e){
e.preventDefault();
});
li ul{
display: none;
}
You could use $(this).find('ul').eq(0) to get the ul, but I would delegate the changing of the display to the stylesheet, but use javascript to add a class where applicable. This will give you many more options for the design of your dropdown later.
$(".drop-nav").on("click", function(e) {
e.preventDefault()
// don't allow the event to fire horizontally or vertically up the tree
e.stopImmediatePropagation()
// switch the active class that you can use to display the child
$(this).toggleClass('active')
})
/* don't target ll list items in you page, be more specific */
.drop-nav > ul {
display: none;
}
.drop-nav.active > ul {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>Profile</li>
<li>Edit</li>
<li class="drop-nav"> See your products
<ul>
<li class="drop-nav"> Mens
<ul>
<li> jumpers </li>
<li> t shirts </li>
</ul>
</li>
<li class="drop-nav"> Womens
<ul>
<li> hoodies </li>
<li> leggings </li>
</ul>
</li>
</ul>
</li>
</ul>
I would add more descriptive class names in your markup, and make them easier to target with CSS and jQuery.
To toggle the menus you could do something like the following:
$(".dropdown-trigger1").on("click", function() {
// Toggle the first menu
$(".dropdown-one").toggleClass("open");
// Close the submenus
$(".dropdown-two").removeClass("open");
});
$(".dropdown-trigger2").on("click", function(e) {
// Prevent a click on a submenu from closing the menu
e.stopPropagation();
// Close any open submenu
$(".dropdown-two").removeClass("open");
// Open the submenu that has been clicked
$(this).find(".dropdown-two").toggleClass("open");
});
li ul {
display: none;
}
.dropdown-one.open {
display: block;
}
.dropdown-two.open {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>Profile</li>
<li>Edit</li>
<li class="dropdown-trigger1"> See your products
<ul class="dropdown-one">
<li class="dropdown-trigger2"> Mens
<ul class="dropdown-two">
<li> jumpers </li>
<li> t shirts </li>
</ul>
</li>
<li class="dropdown-trigger2"> Womens
<ul class="dropdown-two">
<li> hoodies </li>
<li> leggings </li>
</ul>
</li>
</ul>
</li>
</ul>
You haven't described about how you activate each sub-menu, so I will describe solution little bit abstractly. Solution is based on your HTML structure an will work if you wouldn't change it.
$('.drop-nav a').on('click', function() {
// This next method returns next element in DOM that is after clicked a link.
// Based on your HTML it would be ul that holds your sub-menu.
var subMenu = $(this).next();
// Here using subMenu selector to make something with sub-menu...
// Example: adding CSS inline to sub. In your situation it may be something else...
$(subMenu).css({ 'display' : 'block' });
});
Related
I'm working on an application that needs to be fully keyboard controllable, everything is working great up until now, but i can't make the JQuery UI Menu widget works when using the ENTER key.
From the documentation, there seems to be no specifics method to make this work so i'm using "onclick" on the list elements
<li onclick="alert('Books Action')"><div>Books</div></li>
Here is a jsfiddle (https://jsfiddle.net/djbh6r82/) with the example from JQuery UI documentation and an alert on the first menu item -> It works fine when i click on it but with 'ENTER' it just bring me back to the start (focus on menu is not lost)
$(function() {
$("#menu").menu();
});
.ui-menu {
width: 150px;
}
<link rel="stylesheet" href="//code.jquery.com/ui/1.13.0/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.0/jquery-ui.js"></script>
<ul id="menu">
<li class="ui-state-disabled">
<div>Toys (n/a)</div>
</li>
<li onclick="alert('Books Action')">
<div>Books</div>
</li>
<li>
<div>Clothing</div>
</li>
<li>
<div>Electronics</div>
<ul>
<li class="ui-state-disabled">
<div>Home Entertainment</div>
</li>
<li>
<div>Car Hifi</div>
</li>
<li>
<div>Utilities</div>
</li>
</ul>
</li>
<li>
<div>Movies</div>
</li>
<li>
<div>Music</div>
<ul>
<li>
<div>Rock</div>
<ul>
<li>
<div>Alternative</div>
</li>
<li>
<div>Classic</div>
</li>
</ul>
</li>
<li>
<div>Jazz</div>
<ul>
<li>
<div>Freejazz</div>
</li>
<li>
<div>Big Band</div>
</li>
<li>
<div>Modern</div>
</li>
</ul>
</li>
<li>
<div>Pop</div>
</li>
</ul>
</li>
<li class="ui-state-disabled">
<div>Specials (n/a)</div>
</li>
</ul>
Am I doing this wrong ? I tried different thing ( instead of div, onclick on div instead of ul) but nothing seems to work
When you review the API Docs, you will see under https://api.jqueryui.com/menu/ the following details:
Keyboard interaction
ENTER/SPACE: Invoke the focused menu item's action, which may be opening a submenu.
UP: Move focus to the previous menu item.
DOWN: Move focus to the next menu item.
RIGHT: Open the submenu, if available.
LEFT: Close the current submenu and move focus to the parent menu item. If not in a submenu, do nothing.
ESCAPE: Close the current submenu and move focus to the parent menu item. If not in a submenu, do nothing.
Typing a letter moves focus to the first item whose title starts with that character. Repeating the same character cycles through matching items. Typing more characters within the one second timer matches those characters.
Disabled items can receive keyboard focus, but do not allow any other interaction.
So the Enter is already engaged and will trigger the select event for the Menu. You will then want to perform some action in the select callback.
$(function() {
$("#menu").menu({
select: function(e, ui) {
console.log(ui.item.text().trim(), "Selected");
}
}).focus();
});
.ui-menu {
width: 150px;
}
<link rel="stylesheet" href="//code.jquery.com/ui/1.13.0/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.0/jquery-ui.js"></script>
<ul id="menu">
<li class="ui-state-disabled">
<div>Toys (n/a)</div>
</li>
<li>
<div>Books</div>
</li>
<li>
<div>Clothing</div>
</li>
<li>
<div>Electronics</div>
<ul>
<li class="ui-state-disabled">
<div>Home Entertainment</div>
</li>
<li>
<div>Car Hifi</div>
</li>
<li>
<div>Utilities</div>
</li>
</ul>
</li>
<li>
<div>Movies</div>
</li>
<li>
<div>Music</div>
<ul>
<li>
<div>Rock</div>
<ul>
<li>
<div>Alternative</div>
</li>
<li>
<div>Classic</div>
</li>
</ul>
</li>
<li>
<div>Jazz</div>
<ul>
<li>
<div>Freejazz</div>
</li>
<li>
<div>Big Band</div>
</li>
<li>
<div>Modern</div>
</li>
</ul>
</li>
<li>
<div>Pop</div>
</li>
</ul>
</li>
<li class="ui-state-disabled">
<div>Specials (n/a)</div>
</li>
</ul>
Giving it focus up front allows it to already be invoked.
How can I select all the li child of an element in js
I want to select all the li elements of this item (direct child, grand child all)
document.querySelectorAll(".stellarnav li.has-sub").forEach(item =>{
item.addEventListener("click", function(){
console.log(item)
// to make you understand I described it below in css language
// in CSS language it is like this: item li
// then I want to removeAttribute from the all the child
// like this
document.querySelectorAll(`${item} li`).forEach(childItem =>{
childItem.removeAttribute("open");
})
// how can I achive this thing to select all the li childs
// here I tried it but this is not valid
})
});```
Just run this.querySelectorAll('li').forEach(li=>li.removeAttribute("open"));
This is a document querySelectorAll document
Tested code:
document.querySelectorAll(".nav li.has-sub").forEach(item =>{
item.addEventListener("click", function(){
this.querySelectorAll('li').forEach(li=>li.removeAttribute("open"));
})
})
li[open]{
color: red;
}
.nav >li{
margin: 10px
}
<ul class='nav'>
<li class='has-sub'>
this is has-sub li 1
<ul>
<li open>
this is open
</li>
<li open>
this is open
</li>
<li> this is another li
</li>
</ul>
</li>
<li class='has-sub'>
this is has-sub li 2
<ul>
<li open>
this is open
</li>
<li open>
this is open
</li>
<li> this is another li
</li>
</ul>
</li>
<li>
this is li 3
<ul>
<li open>
this is not has-sub open
</li>
<li open>
this is not has-sub open
</li>
<li> this is another li
</li>
</ul>
</li>
</ul>
I made a blog archive in the format of this:
+Year
+Month
Title
Sample code:
<ul>
<span class="toggle">+</span>
<li class="year">$year
<ul>
<span class="toggle">+</span>
<li class="month active">$month
<ul>
<li class="title active">$title</li>
</ul>
</li>
</ul>
</li>
</ul>
I used $(this).next().toggle(), which works fine toggling the lists, but the entire list is expanded in the beginning when the page loads, and I don't want that.
So I changed to changing class names (active/inactive). I want to change the class of the month/title lists to inactive and back when the + span is clicked. The problem is using $(this).next() doesn't work.
If I try $(this).next().hasClass("active");
It will return a false. Or console.log($(this).next().attr("class"));, which gives undefined.
$(this).next().html(); gives:
<li class="month active"><span class="toggle">+</span><ul><li class="title active">...</li></ul></li></ul></li></ul>
The very next thing that follows the + span is the list with class of active, but it doesn't recognize the class? I don't understand why .toggle() works, but this doesn't.
What option do I have to make this work?
The idea is to capture the click event on the span class and toggle active/inactive on the year so that it shows correctly. Here's some psuedo code:
$('.toggle').on('click', function(){
$(this).next().toggleClass('active').toggleClass('inactive');
});
This will only work if the element has a class of inactive on page load, like this:
<ul>
<span class="toggle">+</span>
<li class="year inactive">$year
<ul>
<span class="toggle">+</span>
<li class="month active">$month
<ul>
<li class="title active">$title</li>
</ul>
</li>
</ul>
</li>
</ul>
When you had your initial toggle working but it displayed the items on load, you could have set the next element (the unordered list) to
style="display: none"
As for
console.log($(this).next().attr("class");
You are missing a parenthesis:
console.log( $(this).next().attr("class") );
Hope this helps.
By using little bit of CSS and toggling the class of ul to active only on click will fix your issue. Below is a working example.
$('.toggle').on('click', function() {
$(this).parent().toggleClass('active');
});
ul {
list-style-type: none;
}
ul:not(#MainNode) {
display: none;
}
ul.active > li > ul {
display: block !important;
}
.toggle {
cursor: pointer
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="MainNode">
<span class="toggle">+</span>
<li class="year">Year
<ul>
<span class="toggle">+</span>
<li class="month active">Month
<ul>
<li class="title active">Title</li>
</ul>
</li>
</ul>
</li>
</ul>
I'm trying to change the colour of active menu/submenu which is selected by user.
For example when Sub11 is clicked, Link 1 and Sub11 will both turn red. Likewise when Sub22 is clicked, Link 2 and Sub22 will be red.
ul a { cursor: pointer; }
.active { color:red;}
<ul>
<li class="active"><a>Link 1</a>
<ul>
<li><a>Sub11</a></li>
<li><a>Sub12</a></li>
</ul>
</li>
<li><a>Link 2</a>
<ul>
<li><a>Sub21</a></li>
<li><a>Sub22</a></li>
</ul>
</li>
<li><a>Link 3</a></li>
</ul>
try using jquery this code:
$('.link > a').click(function(){
$('.active').removeClass('active');
$(this).addClass('active');
});
$('.submenu > li').click(function(){
$('.active').removeClass('active');
$(this).addClass('active');
$(this).parent('ul').prev('a').addClass('active');
});
Explanation:
The first part: whenever you click on .link item you remove every other active item and set the clicked one to active.
The second part: whenever you click on a submenu item you remove active state from the previous item and set it to the clicked submenu item and its predecessor .link item
You gonna have to add classes link and submenu to your html like this:
<ul>
<li class="link">
<a class="active">Link 1</a>
<ul class="submenu">
<li><a>Sub11</a></li>
<li><a>Sub12</a></li>
</ul>
</li>
<li class="link">
<a>Link 2</a>
<ul class="submenu">
<li><a>Sub21</a></li>
<li><a>Sub22</a></li>
</ul>
</li>
<li class="link"><a>Link 3</a></li>
</ul>
Here is a fiddle
I have a menu structure in which sub menus are present as nested lists like this
<nav>
<ul>
<li class="itm">A
<ul>
<li>One</li>
<li>Two
<ul>
<li>Menu Item</li>
<li> Menu Item </li>
<li> Menu Item </li>
</ul>
</li>
<li> Three </li>
<li> Four </li>
</ul>
</li>
<li class="icon"><span class="img"></span></li>
<li class="itm">B</li>
<li class="itm">C</li>
</ul>
</nav>
Nowi want to show the sub menu (sub list) when the cursor hovers over the parent li and for that I am doing this:
$('nav ul li').hover(function () {
console.log(this);
$(this > ul).fadeIn();
}, function () {
$(this > ul).fadeOut();
});
But on hover it showing this error in JS Console: Uncaught ReferenceError: ul is not defined
Your selector is combining this, which is a literal, and what should be a string in a selector (> ul). ul is being treated as a variable, and the ul variable doesn't exist.
Try this:
http://jsfiddle.net/cyzsw/
$(this).children('ul').fadeIn();