JS: how can I select a child in event.target? - javascript

I have a nested megu menu like this:
<ul class="nav-wrap">
<li class="main-nav">
<a>m1</a>
<ul class="sub-nav">
<li></li>
...
<li><ul>...</ul><li>
</ul>
<li>
<li class="main-nav">
<a>m1</a>
<ul class="sub-nav"></ul>
<li>
<li class="main-nav">
<a>m1</a>
<ul class="sub-nav"></ul>
<li>
...
</ul>
for each main-nav, I want hover main-nav, and add .show class in .sub-nav (its child).
how can I do that?
I try this:
var dropdownMenus = [].slice.call(document.querySelectorAll('.main-nav'));
var dropdownList = dropdownElementList.map(function (dropdownToggleEl) {
dropdownToggleEl.onmouseover= function(e){
e.target.children.querySelector('ul.sub-nav').classList.toggle('show');
};
dropdownToggleEl.onmouseleave= function(e){
e.target.children.querySelector('ul.sub-nav').classList.toggle('show');
};
});
But I get this error:
net::ERR_CERT_DATE_INVALID
Uncaught TypeError: e.target.children.querySelector is not a function at HTMLLIElement.dropdownToggleEl.onmouseover

There is code missing in multiple places in JS, HTML and CSS, I've added the missing pieces. Use onmouseenter instead of onmouseover as it always provides the same element on which you added the event listener for e.target while same is not true for onmouseover.
let dropdownElementList = [].slice.call(document.querySelectorAll('.main-nav'));
dropdownElementList.map(function (dropdownToggleEl) {
dropdownToggleEl.onmouseenter= function(e){
e.target.querySelector('ul.sub-nav').classList.remove('hide');
e.target.querySelector('ul.sub-nav').classList.add('show');
};
dropdownToggleEl.onmouseleave= function(e){
e.target.querySelector('ul.sub-nav').classList.remove('show');
e.target.querySelector('ul.sub-nav').classList.add('hide');
};
});
.show {
display: block;
}
.hide {
display: none
}
<ul class="nav-wrap">
<li class="main-nav">
<a>m111</a>
<ul class="sub-nav hide">
<li>m1.s11</li>
<li>m1.s22</li>
<li><ul>...</ul></li>
</ul>
</li>
<li class="main-nav">
<a>m122</a>
<ul class="sub-nav hide">
<li>m2.s11</li>
<li>m2.s22</li>
</ul>
</li>
<li class="main-nav">
<a>m133</a>
<ul class="sub-nav"></ul>
</li>
...
</ul>

Related

Nested dropdrown menu

I'm trying to build a nested dropdown menu with javascript and click event. My html is this:
<ul>
<li id="menu-item-439" class="dropdown">
hostelerĂ­a
<ul class="sub-menu">
<li id="menu-item-459">
Comanderos
</li>
<li id="menu-item-457" class="dropdown">
Venta online
<ul class="sub-menu">
<li>
PortalRest Pedidos
</li>
</ul>
</li>
</ul>
</li>
</ul>
and my javascript:
document.querySelectorAll('.dropdown').forEach(i => {
i.addEventListener('click', (e) => {
i.classList.toggle('show');
})
});
The problem is in the nested "dropdown" class. When i click in "child dropdown" (id="menu-item-457") toogle not only affects that element but also affects the parent (id="menu-item-439")
Thanks!!
Here
HTML
<ul>
<li id="menu-item-439" class="dropdown">
hostelerĂ­a
<ul class="sub-menu">
<li id="menu-item-459">
Comanderos
</li>
<li id="menu-item-457" class="dropdown">
Venta online
<ul class="sub-menu">
<li>
PortalRest Pedidos
</li>
</ul>
</li>
</ul>
</li>
</ul>
JS
let n=0, n2=0;
function toggle() {
n++;
if (n%2==0) {
document.getElementsByClassName("sub-menu")[0].style.display="none";
}
else {
document.getElementsByClassName("sub-menu")[0].style.display="block";
}
}
function toggle2() {
n2++;
if (n2%2==0) {
document.getElementsByClassName("sub-menu")[1].style.display="none";
}
else {
document.getElementsByClassName("sub-menu")[1].style.display="block";
}
}
CSS
.sub-menu {display: none}
If you wanted same with JQuery toggle method, then js should be like this
JS
function toggle() {
document.getElementsByClassName("sub-menu")[0].toggle();
}
function toggle2() {
document.getElementsByClassName("sub-menu")[1].toggle();
}

jQuery toggle text color from self and removing from others

I'm new to jQuery/js, and I'm trying to toggle colors on click with jQuery.
I need something like this:
When I click an item, it toggles a class to change color.
If I click an item once, it changes color. Then if I click another item it changes color, but the other items must return to their initial color.
I can manage to toggle each item color, but I'm unable to remove the class color from the others.
Only the <li> with the class submenu-toggler should change colors. The 2nd level ul should not have their lis changed.
The final code looks something like this:
$(".submenu-toggler a").click(function(){
$(this).siblings().removeClass('red');
$(this).toggleClass("red");
});
a {
color: gray;
}
.red {
color: red;
}
li {
list-style-type: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="main-nav-menu" class="menu-hide">
<li>Item1</li>
<li class="submenu-toggler">
Toggler<span></span>
<ul id="submenu-1" class="main-nav-submenu">
<li>sub1</li>
<li>sub2</li>
<li>sub3</li>
<li>sub4</li>
</ul>
</li>
<li>Item3</li>
<li>Item4</li>
<li class="submenu-toggler">
Toggler<span></span>
<ul id="submenu-2" class="main-nav-submenu">
<li>sub1</li>
<li>sub2</li>
<li>sub3</li>
</ul>
</li>
<li>Item6</li>
</ul>
I believe this is what you are looking for, by using .siblings() all what you have to do is to remove class .red from the siblings elements and then perform the toggle on the current clicked element
Update: its working now for other elements, note that I added a selector .red * to make sub-elements also colored in red:
$(".item").click(function(){
$(this).siblings().removeClass('red');
$(this).toggleClass("red");
});
li {
color: grey;
}
.red,
.red *{
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li class="item"><a>Item 1</a></li>
<li class="item"><a>Item 2</a></li>
<li class="item">
<a>Item 3</a>
<span>AA</span>
<ul>
<li>AA</li>
<li>AA</li>
</ul>
</li>
</ul>
<ul id="main-nav-menu" class="menu-hide">
<li class="item">Item1</li>
<li class="item submenu-toggler">
Toggler<span></span>
<ul id="submenu-1" class="main-nav-submenu">
<li>sub1</li>
<li>sub2</li>
<li>sub3</li>
<li>sub4</li>
</ul>
</li>
<li class="item">Item3</li>
<li class="item">Item4</li>
<li class="item submenu-toggler">
Toggler<span></span>
<ul id="submenu-2" class="main-nav-submenu">
<li>sub1</li>
<li>sub2</li>
<li>sub3</li>
</ul>
</li>
<li class="item">Item6</li>
</ul>

How to toggle nested lists using button

I've created a list with nesting and added a button to every parent <li> element. The list looks like this:
$("#pr1").append("<button id='bnt-cat13' class='buttons-filter'>expnd1</button>");
$("#pr2").append("<button id='bnt-cat13' class='buttons-filter'>expnd2</button>");
$("#pr3").append("<button id='bnt-cat13' class='buttons-filter'>expnd3</button>");
$(document).ready(function() {
$("button").click(function() {
$('li > ul').toggle();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="categories">
<li>1</li>
<li class="parent" id="pr1">2
<ul class="children">
<li>2.1</li>
</ul>
</li>
<li>3</li>
<li class="parent" id="pr2">4
<ul class="children">
<li>4.1</li>
<li class="parent" id="pr3">4.2
<ul class="children">
<li>4.2.1</li>
</ul>
</li>
</ul>
</li>
<li>5</li>
</ul>
But this one toggles all list, instead of toggling only separate nested list?
How to show/hide only separate nested lists clicking the buttons?
Thanks in advance.
As for the main question - instead of each li > ul elements, you have to toggle only the ul element which is right before a button. So you should use .prev()
$("button").click(function() {
$(this).prev().toggle();
});
$("#pr1").append("<button id='bnt-cat131' class='buttons-filter'>expnd1</button>");
$("#pr2").append("<button id='bnt-cat132' class='buttons-filter'>expnd2</button>");
$("#pr3").append("<button id='bnt-cat133' class='buttons-filter'>expnd3</button>");
$(document).ready(function() {
$("button").click(function() {
$(this).prev().toggle();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="categories">
<li>1</li>
<li class="parent" id="pr1">2
<ul class="children">
<li>2.1</li>
</ul>
</li>
<li>3</li>
<li class="parent" id="pr2">4
<ul class="children">
<li>4.1</li>
<li class="parent" id="pr3">4.2
<ul class="children">
<li>4.2.1</li>
</ul>
</li>
</ul>
</li>
<li>5</li>
</ul>
Your code has another issue that should be fixed - each button has the same id attribute (bnt-cat13).
The id global attribute defines a unique identifier (ID) which must be unique in the whole document.
Change your function into:
(document).ready(function() {
$("button").click(function() {
$(this).parent().children('ul').toggle();
});
});

How to get a previous DIV with jQuery

I want to animate an element (.item-i) after I click on another element(.item-1) which is following below. Now I don't know, how to get to this element.
I want only the exact above element animated, not both above, only the first element above.
I made an easy show up in http://jsfiddle.net/Eef4v/1/. The YellowBG is the "animation".
Here is my JS code:
$('.item-1').click(function() {
$(this).closest('.item-i').css( "background", "yellow" );
});
And my HTML Markup:
<ul id="one" class="level-1">
<li class="item-i">I</li>
<li class="item-ii">II
<ul class="level-2">
<li class="item-a">A</li>
<li class="item-b">B
<ul class="level-3">
<li class="item-1">1</li>
<li class="item-2">2</li>
<li class="item-3">3</li>
</ul>
</li>
<li class="item-c">C</li>
</ul>
</li>
<li class="item-iii">III</li>
</ul>
<ul id="Ul1" class="level-1">
<li class="item-i">I</li>
<li class="item-ii">II
<ul class="level-2">
<li class="item-a">A</li>
<li class="item-b">B
<ul class="level-3">
<li class="item-1">1</li>
<li class="item-2">2</li>
<li class="item-3">3</li>
</ul>
</li>
<li class="item-c">C</li>
</ul>
</li>
<li class="item-iii">III</li>
</ul>
Use:
$(this).closest('.item-ii').prev().css( "background", "yellow" );
Working Demo
For Toggling background color:
$(this).closest('.item-ii').prev().toggleClass("highlight");
CSS:
.highlight {background: yellow;}
Demo with ToggleClass
Two ways to get .item-i to highlight.
$(this).parents('.level-1').find('.item-i').css( "background", "yellow" );
but if you have multiple .item-i classes under your .level-1 then they would all turn yellow.
Working Demo
You could also write a find algorithm that goes through each parent of .item-1 and finds the closest item-i
$('.item-1').click(function () {
$(this).parents().each(function(index,elem){
var query = $(elem).find('.item-i');
if(query.length > 0)
{
query.first().css("background-color", "yellow");
return false;
}
});
});
Working Algorithm demo

open the first section when page loads

HTML:
<li class="page_item ">
A
<ul class="children">
<li class="page_item">1</li>
<li class="page_item">2</li>
</ul>
</li>
<li class="page_item ">
B
<ul class="children">
<li class="page_item">1</li>
<li class="page_item">2</li>
<li class="page_item">3</li>
<li class="page_item">4</li>
</ul>
</li>
<li class="page_item ">
C
<ul class="children">
<li class="page_item">1</li>
<li class="page_item">2</li>
<li class="page_item">3</li>
<li class="page_item">4</li>
</ul>
</li>
JS:
$('.page_item').click(function() {
var that = this;
$('.page_item').each(function() {
if (that == this) return true; //continue
$('.children:not(:hidden)', this).slideToggle();
});
$('ul.children', this).slideToggle();
});
Online demo: http://jsfiddle.net/kHLuR/1/
How can I make the first section li opened by default?
Variant #1 Pure CSS solution:
.page_item:first-child .children {
display: block;
}
Demo: http://jsfiddle.net/dfsq/kHLuR/7/
Note: :first-child works in IE8+. If you need to support older version you can give another class to your first li, e.g: <li class="page_item page_item-first"> http://jsfiddle.net/dfsq/kHLuR/9/
Variant #2. Trigger click event on the first .page_item:
$('.page_item').click(function () {
// ...
})
.filter(':first').click();
Demo: http://jsfiddle.net/dfsq/kHLuR/8/
Add this code to simulate a click event when the page is loaded: LIVE DEMO
$(document).ready(function () {
$('a').eq(0).trigger('click');
});
You can use jQuery's .ready() to execute code immediately after the page loads.
Take a look at http://api.jquery.com/ready/

Categories

Resources