I am following a css flex video and I am trying to build a menu with several levels. I am using jQuery to open and close a menu and sub-menu, and sub-sub-menu, etc.
Here is my demo.
- I click on "Contact"
- Then, I clik on "A propo" and "Contact" should close.
- I click on the first sub-menu (Item 1.2) => The first level should not close
- I click on the second sub-menu (Item 1.2.3) => All of this direct ul parent, should not close.
- Then now, when I click again to "Contact", all menu and sub-menus of "A propos" should close
My problem, I do not know how to target the first level of li.hasChildren and check all of child of other ul li.hasChildren and look for the children to close the opened menu and sub-menu.
Here is my script to close/open the selected menu, which works
( function( $ ) {
$( '.dropdown-toggle' ).click( function( e ) {
var _this = $( this );
e.preventDefault();
_this.toggleClass( 'toggled-on' );
_this.find('.fa').toggleClass( 'fa-angle-down fa-angle-up');
_this.parent().next( '.sub-menu' ).toggleClass( 'toggled-on' );
_this.attr( 'aria-expanded', _this.attr( 'aria-expanded' ) === 'false' ? 'true' : 'false' );
// HOW CAN I CHECK ALL OTHER MENUS
} );
})( jQuery );
Above, I created a variable _this
- How can I check for the first
li.hasChildren
from_this
- Then how can check if there is other parent
li.hasChildren
up to the first level of li - Then how can check all other branch of the tree to close the ul-su-menu bellow li.hasChildren, excepted for the tree that the click come from
I tried with parentUntil()
(this).parentsUntil("li.hasChildren").css( "background-color", "red" );
to mark with a class first level, but I apparently jQuery stop at the first li.hasChildren it meet, and do not continue until the first level
Note, when a menu or sub-menu is open, the ul take the class ul.toggled-on
. To close a sub-menu, we can use removeClass('.toggled-on')
here is my html code
<nav role="navigation" aria-label="Main navigation">
<ul >
<li >
<div>
<a href="#">A propo</a>
<a href="#" aria-expanded="false">
[12]
<i ></i>
</a>
</div>
<ul role="group">
<li>
<div>
<a href="#">Item 1.1</a>
</div>
</li>
<li >
<div>
<a href="#" >Item 1.2</a>
<a href="#" aria-expanded="false">
[1]
<i ></i>
</a>
</div>
<ul role="group">
<li>
<div>
<a href="#">Item 1.2.1</a>
</div>
</li>
<li>
<div>
<a href="#">Item 1.2.2</a>
</div>
</li>
<li >
<div>
<a href="#">Item 1.2.3</a>
<a href="#" aria-expanded="false">
[1]
<i ></i>
</a>
</div>
<ul >
<li><div><a href="#">Item 1.2.3.1</a></div></li>
<li><div><a href="#">Item 1.2.3.2</a></div></li>
<li><div><a href="#">Item 1.2.3.3</a></div></li>
</ul>
</li>
</ul>
</li>
<li>
<div>
<a href="#">Item 333333</a>
</div>
</li>
</ul>
</li>
<li>
<div>
<a href="#">Team</a>
</div>
</li>
<li >
<div>
<a href="#" >Contact</a>
<a href="#" aria-expanded="false">
[13]
<i ></i>
</a>
</div>
<ul role="group">
<li>
<div>
<a href="#">Adresse</a>
</div>
</li>
<li>
<div>
<a href="#">Téléphone</a>
</div>
</li>
<li>
<div>
<a href="#">e-mail</a>
</div>
</li>
</ul>
</li>
<li>
<div>
<a href="#">Nos cours</a>
</div>
</li>
<li>
<div>
<a href="#">Menu 3</a>
</div>
</li>
<li>
<div>
<a href="#">Encore un beau menu 4</a>
</div>
</li>
<li>
<div>
<a href="#">Contact</a>
</div>
</li>
</ul>
</nav>
Then my question is, how can I check all ul.toggled-on, which does not belong of the branch where I clicked
Many thanks
CodePudding user response:
I finally found a solution as the following
( function( $ ) {
$( '.dropdown-toggle' ).click( function( e ) {
e.preventDefault();
//console.log( e ": " $( this ).siblings('a').text() );
// Add or remove the toggled-on class and change the aria-expand status of the link
$(this).toggleClass('toggled-on').attr('aria-expanded',$(this).attr('aria-expanded') === 'false' ? 'true' : 'false')
.find('.fa').toggleClass('fa-angle-down fa-angle-up')
// find the closest parent div and go to the first ul.sub-menu, then add/remove the class toggled-on to the ué
.closest('div').eq(0).next('ul').toggleClass('toggled-on')
// Go up to the closest hasChildren class and look at all system/brother of .hasChildren
.closest('.hasChildren').eq(0).siblings(".hasChildren")
// Find .dropdown-toggle and do a forwach for all of them
.find('.dropdown-toggle').each(function(){
$('#breadcrumb').text('');
//$(this).css("background-color", "blue");
// remove the toggled-on class and change the axia-expanded status of each links
$(this).removeClass('toggled-on').attr('aria-expanded','false')
// change the icon
.find('.fa').removeClass('fa-angle-up').addClass('fa-angle-down')
// move up to the closest div and go to the next ul (ul.sub-menu) and remove the toggled-on class to close the menu
.closest('div').eq(0).next('ul').removeClass('toggled-on');
});
$('#breadcrumb').append(' / ' $( this ).siblings('a').text());
} );
})( jQuery );
I hope, you will like it
CodePudding user response:
You can set a class active for the last click on your menus.
Like this, you can do a loop with each() and check for unactive menu.
I commented my code.
( function( $ ) {
$( '.dropdown-toggle' ).click( function( e ) {
$( '.dropdown-toggle' ).removeClass('active');
var _this = $( this );
e.preventDefault();
_this.toggleClass( 'toggled-on' );
_this.find('.fa').toggleClass( 'fa-angle-down fa-angle-up');
_this.parent().next( '.sub-menu' ).toggleClass( 'toggled-on' );
_this.attr( 'aria-expanded', _this.attr( 'aria-expanded' ) === 'false' ? 'true' : 'false' );
_this.addClass( 'active' );
// check if link has submenu
var checkIfSubMenu = _this.parent('div:first').nextAll('ul.sub-menu:first');
//console.log(checkIfSubMenu.length);
// check for inactive toogled menu
var checkIfNotActiveSubMenu = $( 'a.toggled-on:not(.active)' );
//console.log(checkIfNotActiveSubMenu.length);
// close inactive menu
$('.toggled-on').each(function() {
// we get the link in the previous div and check if the link dont have class active
if (!$(this).prevAll('div:first').find('.dropdown-toggle').hasClass('active')) {
// so we remove class for the submenu
$(this).removeClass('toggled-on');
}
});
// HOW CAN I CHECK ALL OTHER MENUS
} );
$( '.e-panel ul li div a:not(.dropdown-toggle, .link)' ).click( function( e ) {
$('.toggled-on').removeClass('toggled-on');
});
})( jQuery );
.bg-black{
background-color: black;
color: white;
}
.bg-black a{
color: white;
text-decoration: none;
}
.bg-black li:hover{
color: white;
text-decoration: none;
}
.red{
border: 4px solid #ff22ff;
}
/* GENERAL */
/* ul li */
i{
width: 8px;
}
/* First level */
nav.e-panel-row ul{
margin: 0 auto;
list-style: none;
box-sizing: border-box;
padding: 0px;
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: space-between;
border: 1px solid red;
}
nav.e-panel-row ul li{
font-size: 1em;
/*border: solid 3px red !important;*/
position: relative;
flex: 1 0 auto;
}
nav.e-panel-row ul li div{
padding: 10px;
}
/* hasChildren */
nav.e-panel-row ul li.hasChildren{
}
nav.e-panel-row ul li.hasChildren ul.sub-menu{
display: none;
border: 1px solid green;
position: absolute;
z-index: 1000;
background-color: #666;
width: 100%;
}
nav.e-panel-row ul li.hasChildren ul.sub-menu.toggled-on{
display: flex;
flex-wrap: wrap;
flex-direction: column;
box-sizing: border-box;
border: 1px solid red;
}
nav.e-panel-row ul li.hasChildren ul.sub-menu.toggled-on li{
flex: 1 1 auto;
}
nav.e-panel-row ul li.hasChildren ul.sub-menu.toggled-on li.hasChildren ul.sub-menu{
position: relative;
}
nav.e-panel-row ul li:hover, section.e-panel-row nav ul li:hover,
background-color: #333333;
}
.toggle-on{display:inline-block}
.sub-menu{display:none}
.sub-menu.toggled-on{display:block}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section >
<div >
<h2>Row</h2>
</div>
<nav aria-label="Main navigation">
<ul >
<li >
<div>
<a href="#">A propo</a>
<a href="#" aria-expanded="false">
[12]
<i ></i>
</a>
</div>
<ul role="group">
<li>
<div>
<a href="#">Item 1.1</a>
</div>
</li>
<li >
<div>
<a href="#" >Item 1.2</a>
<a href="#" aria-expanded="false">
[1]
<i ></i>
</a>
</div>
<ul role="group">
<li>
<div>
<a href="#" >Item 1.2.1</a>
</div>
</li>
<li>
<div>
<a href="#" >Item 1.2.2</a>
</div>
</li>
<li >
<div>
<a href="#">Item 1.2.3</a>
<a href="#" aria-expanded="false">
[1]
<i ></i>
</a>
</div>
<ul >
<li><div><a href="#" >Item 1.2.3.1</a></div></li>
<li><div><a href="#" >Item 1.2.3.2</a></div></li>
<li><div><a href="#" >Item 1.2.3.3</a></div></li>
</ul>
</li>
</ul>
</li>
<li>
<div>
<a href="#" >Item 333333</a>
</div>
</li>
</ul>
</li>
<li >
<div>
<a href="#" >Team</a>
<a href="#" aria-expanded="false">
[3]
<i ></i>
</a>
</div>
<ul role="group">
<li>
<div>
<a href="#" >Direction</a>
</div>
</li>
<li>
<div>
<a href="#" >Secrétaires</a>
</div>
</li>
<li>
<div>
<a href="#" >Collaborateurs</a>
</div>
</li>
</ul>
</li>
<li >
<div>
<a href="#" >Contact</a>
<a href="#" aria-expanded="false">
[13]
<i ></i>
</a>
</div>
<ul role="group">
<li>
<div>
<a href="#" >Adresse</a>
</div>
</li>
<li>
<div>
<a href="#" >Téléphone</a>
</div>
</li>
<li>
<div>
<a href="#" >e-mail</a>
</div>
</li>
</ul>
</li>
<li >
<div>
<a href="#" >Nous cours</a>
<a href="#" aria-expanded="false">
[3]
<i ></i>
</a>
</div>
<ul role="group">
<li>
<div>
<a href="#" >CSS</a>
</div>
</li>
<li>
<div>
<a href="#" >Django</a>
</div>
</li>
<li>
<div>
<a href="#" >React</a>
</div>
</li>
</ul>
</li>
<li>
<div>
<a href="#">Menu 3</a>
</div>
</li>
<li>
<div>
<a href="#">Encore un beau menu 4</a>
</div>
</li>
<li>
<div>
<a href="#">Contact</a>
</div>
</li>
</ul>
</nav>
</section>