MetisMenu Third Level Always Collapse - javascript

I'm using MetisMenu, when I have a link on a third layer menu item the parent menu items all collapse once the link has been clicked.
The second level menu itme links work correctly.
My sample code is here:
<div class="navbar-default sidebar" role="navigation">
<div class="sidebar-nav navbar-collapse">
<ul class="nav in" id="side-menu">
<li>
<i class="fa fa-sitemap fa-fw"></i> Multi-Level Dropdown<span class="fa arrow"></span>
<ul class="nav nav-second-level collapse">
<li> Works Correctly!</li>
<li>
Third Level <span class="fa arrow"></span>
<ul class="nav nav-third-level">
<li> DOES NOT WORK - ALWAYS COLLPOASE PARENTS</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
enter code here

Similar issue and similar solution to the one above, only adding adding class active to all nested <li>. This allows the chevron-right to be a chevron-down.
var url = window.location;
var element = $('ul.nav a').filter(function () {
return this.href == url;
});
if (element) {
element.addClass('active').parents('#side-menu ul').addClass('in');
element.parents('#side-menu li').addClass('active');
}

We recently encountered this problem, a lot of debugging showed, that the problem was with how sb-admin marked html elements as active (specifically, "li" tags).
The file in question is sb-admin-2.js. Down at the bottom it has the following bit of code:
var url = window.location;
var element = $('ul.nav a').filter(function() {
return this.href == url || url.href.indexOf(this.href) == 0;
}).addClass('active').parent().parent().addClass('in').parent();
if (element.is('li')) {
element.addClass('active');
}
First, sb-admin calculates the depth level of your URL and uses this number to index child elements. It then uses this number to iterate through the particular branch of the DOM tree bottom-to-top. It then marks these elements as "active".
In our case the URL wouldn't change, but the number of elements would (for three-levels deep structure it would be 3, but the index remained 2). So, the third and second level elements would become active, but everything else is marked passive, so the top element would collapse, hiding the whole sub-menu.
This is how we fixed it (I'm not a JS guy, so I don't know how good this solution is, but it works):
var url = window.location;
$('ul.nav a').filter(function () {
return this.href == url || url.href.indexOf(this.href) == 0;
}).addClass('active').parents('#side-menu ul').addClass('in');
HTH

var url = window.location;
// var element = $('ul.nav a').filter(function() {
// return this.href == url;
// }).addClass('active').parent().parent().addClass('in').parent();
var element = $('ul.nav a').filter(function() {
return this.href == url;
}).addClass('active').parent();
// while (true) {
// if (element.is('li')) {
// element = element.parent().addClass('in').parent();
// } else {
// break;
// }
// }
This will do the trick guysenter image description here

Related

Dynamically add class based on page

I have a navagation list written with bootstrap css:
<ul class="nav navbar-nav navbar-right">
<li class="">Home</li>
<li class="">About</li>
</ul>
My question is how can I use javascript to add the class "active" to the "li" tags using javascript? I want it to have the active class on index.html for home and the same for about.html
Is this possible?
JavaScript
var siteList = document.URL.split("/");
var site = siteList[siteList.length - 1];
var list = document.getElementsByTagName("li");
for (var index = 0; index < list.length; index++) {
var item = list[index];
var link = item.firstElementChild;
var href = link ? String(link.href) : "-";
if (href.replace(".html","") === site) {
item.classList.add("open");
} else {
item.classList.remove("open");
}
}
Explanation
You can get the current URL using document.URL, you probably want the just the last part, so you'll have to split it and get the last part, which in your case will be index, about etc.
Then get all the li elements and iterate through them.
If they don't have an a child then ignore it.
If they do get the href attribute and remove the .html at the end.
If that text is the same as the site variable, then that means you should open the element, otherwise close it.
It's not clean, and there's probably a better way to do it, but:
HTML
<ul class="nav navbar-nav navbar-right">
<li id="navIndex" class="">Home</li>
<li id="navAbout" class="">About</li>
</ul>
JS (somewhere)
// Map ids with html page names
var pages = {
navIndex: "index.html",
navAbout: "about.html"
};
// Iterate over map
for(var property in pages) {
// Check to make sure that the property we're iterating on is one we defined
if(pages.hasOwnProperty(property)) {
// indexOf will be 0+ if it appears in the string
if(window.location.href.indexOf(pages[i]) > -1) {
// we can use property because we defined the map to be same as ids
// From https://stackoverflow.com/questions/2739667/add-another-class-to-a-div-with-javascript
var el = document.getElementById(property);
el.className += el.className ? ' active' : 'active';
break; // no need to keep iterating, we're done!
}
}
}
This is more or less a "dirty" approach because it requires more than just JavaScript to get to work (see Nick's answer for a cleaner implementation).
First we set identifiers on our <li> elements, then we map out those identifiers with their respective href attributes.
Once we have the <li>s mapped out, we then iterate over the map's keys (which we set to be the id attributes on our <li>s) and check if the href attribute is present within the site's window.location.href, if it is: add the active class and stop searching, otherwise we keep on trucking.

active class on menu and parent item

i have this HTML code for my menu:
<nav id="main-navigation" class="navigation-simple">
<ul>
<li>Home</li>
<li><a class="active-nav" href="">About Us</a>
<ul>
<li><a class="active-nav" href="about">About</a></li>
<li>Testimonials</li>
<li>Meet The Team</li>
</ul>
</li>
</nav>
i have added in the active-nav class but how can i automatically set the active class on parent and child items when the current URL is the href value of the link?
you need java script for this, jQuery is great for beginners!
It could be done like this:
var url = window.location.href;
$( "nav li a" ).each(function(index) {
if (url.indexOf($(this).attr('href')) >= 0){
$(this).addClass('active-nav');
}
});
line by line -
get the current page url
for each link in the navigation...
check if its href is in the current url
if it is, add the class 'active-nav'
close if statement
close for loop
You can use the .filter() method to find the appropriate link and add the required class:
$('#main-navigation li > a').removeClass('active-nav')
.filter(function() {
return location.href.indexOf(this.href) > -1;
})
.addClass('active-nav') //add class to matched element(s)
//add class to parent(s) of matched, if any
.each(function() {
$($(this).parents('a'), '#main-navigation').addClass('active-nav');
});
Also remember to close your first ul.
Something like:
$(function() {
$('#main-navigation a').each(function() {
if(this.href.indexOf(window.location.pathname) === 0) {
$(this).addClass('active-nav');
} else {
// case when something was set to active by the server
$(this).removeClass('active-nav');
}
});
});
will do the job.
Make sure you make the if condition safe to your sites deeplinking implementation (e.g. GET params, anchors or multiple domains with same pathname are possible within your navigation).

Check page title is contained within link attribute and assign active class using jQuery

I'm building a jQuery function to change the colour of the link of my navigation bar. I want to identify the data attribute of a link in the navigation bar and compare it to the current title of the page.
I then want to see if the current page title contains the anchor tags data attribute and if so addClass("active"); if the result is true. A key requirement is it to not match case as well.
Here is my corresponding html and javascript
<ul class="top nav">
<li><a class="first" href="http://www.fishwebsite/" name="link" data-index="Home">Home</a></li>
<li>About us</li>
<li>Our boats</li>
<li>Product list</li>
<li>Recipes</li>
<li>Contact us</li>
</ul>
And the javascript currently is
var current_title = (document).attr("title");
$("a[name=link]").each(function () {
var a = $("a[name=link]").attr("data-index");
//returns true or false...
var exists = current_title.test(a);
if(exists) {
$(a).addClass("active");
}
else {
//false statement..do whatever
}
});
Can someone help me along? I have a CSS style for an active link which will be different to usual nav items hence giving the impression its the 'active' page on the site.
Change to $(this) in each function since, you are selecting each item.
var current_title = (document).attr("title");
$("a[name=link]").each(function () {
var a = $(this).attr("data-index");
//returns true or false...
var exists = current_title.test(a);
if(exists) {
$(this).addClass("active");
}
else {
//false statement..do whatever
}
});
Try this,Wrap your script inside document ready. and I changed your functions little bit.
<script>
$(document).ready(function(){
var current_title = $(document).attr("title");
$("a[name=link]").each(function () {
var a = $(this).attr("data-index");
//returns true or false...
var exists = current_title.indexOf(a)>0;
if(exists) {
$(a).addClass("active");
}
else {
//false statement..do whatever
}
});
});
</script>
I have now fixed the issue thanks to both posts above. Here is the complete HTML and JS.
<ul class="top nav">
<li><a class="first" href="http://www.fishwebsite/" name="link" data-index="Home">Home</a></li>
<li>About us</li>
<li>Our Boats</li>
<li>Product list</li>
<li>Recipes</li>
<li>Contact us</li>
</ul>
And the Javascript
$(document).ready(function() {
var current_title = $(document).attr("title");
$("a[name=link]").each(function() {
var a = $(this).attr("data-index");
var exists = current_title.indexOf(a)>0;
if(exists) {
$(this).addClass("active")
}
else {
// $(this).removeClass('active');
}
});
});
Adding $(this) instead of (a) was a great tip as it singled out the link in question and Nishans addition of >0 finished off the working code.
Drawbacks
Case sensitivity. The data-index value must match the case of the title exactly or the active link will not be assigned.
Longer anchor tags with the addition of a name attribute and data-index.
Advantages
An efficient way to assign an active link with jQuery and title and data-index can be matched up in case very easily when building websites. No server side, messy PHP intervention to assign an active link.

dynamically apply active class to nav li

I have included a header to my files as in include. In the header is the nav bar.
How do I, using jQuery, apply class="active" to the relevant li.
The only way I could think of doing it is to set a variable on the actual pages, apply an id that is equal to that variable of the relevant page and if function so if they match apply a class to the li.
However, I thought there must be a simpler way of achieving this.
<ul class="nav nav-pills right" id="div">
<li id="home" class="active">
Home
</li>
<li id="search">
Search
</li>
<li id="contact">
Contact
</li>
</ul>
An easy way to do this would be to have a script per page:
$('#home').addClass('active'); // for home page
You could try and match the href to the current url:
var path = window.location.pathname.substring(1);
$('.nav>li>a[href="' + path + '"]').parent().addClass('active');
More compact way:
$(function(){
var sPath = window.location.pathname;
var sPage = sPath.substring(sPath.lastIndexOf('/') + 1);
$('a[href="'+ sPage +'"]').parent().addClass('active');
});
As soon as the page loads it will run this code:
$(document).ready(function(){
$('li').removeClass('active');
$('li a').each(function() {
$found = $.contains($(this).prop("href"),location.pathname);
if ($found) {
$(this).closest('li').addClass('active');
break;
}
});
});
OR
You can also do this using regex :
$(document).ready(function(){
$('li').removeClass('active');
var regex = /[a-z]+.php/g;
var input = location.pathname;
if(regex.test(input)) {
var matches = input.match(regex);
$('a[href="'+matches[0]+'"]').closest('li').addClass('active');
}
});
You might need to have the similar id name to that of php file.
Check the demo here : Demo
You can do this:
//remove the active class from all items, if there is any
$('.nav>li').removeClass('active');
//finally, add the active class to the current item
$('a[href='+ location.pathname.substring(1) +']').parent().addClass('active');
You could use javascript to find the current list item based on the url, by adding the class to the right list item after the DOM has been loaded (e.g. string manipulation of window.location together with JQuery selectors and addClass())
I found a routine to set active (current) class on my shared menu, but I need to modify it to set the parent link only, and not the 'closest' link. It works great on menu items with no sub menus, but when a sub menu item is clicked, there is not indication on the main menu after page load. (the code I need to modify is below)
(function( $ ) {
$.fn.activeNavigation = function(selector) {
var pathname = window.location.pathname
var extension_position;
var href;
var hrefs = []
$(selector).find("a").each(function(){
// Remove href file extension
extension_position = $(this).attr("href").lastIndexOf('.');
href = (extension_position >= 0) ? $(this).attr("href").substr(0, extension_position) :
$(this).attr("href");
if (pathname.indexOf(href) > -1) {
hrefs.push($(this));
}
})
if (hrefs.length) {
hrefs.sort(function(a,b){
return b.attr("href").length - a.attr("href").length
})
hrefs[0].closest('li').addClass("current")
}
}; })(jQuery);
If someone still checks on google how to do it here is my solution
var path = window.location.href; // full url
$('a[href="'+ path +'"]').parent().addClass('active'); // find by selector url
HTML
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="http://example.com/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://example.com/history"> History</a>
</li>
</ul>

How can i change the css class based on keywords in url with jquery

I have the navigation bar as below
<ul>
<li class="selected"><a href=">My Profile</a></li>
<li>xxxx</li>
<li>mybook</li>
<li>Photos <span>4</span></li>
<li>Profile List</li>
</ul>
I want that if the url is www.abc.com/user/profile then profile tab class should have class selected attached
If photos then photo tab.
If we can have partial match that will be good but i am not sure if thats possible
like in url i have /user/book and myBook gets selected
Some elegant variant:
<ul class="menu">
<li><a class="profile" href="/user/profile">My Profile</a></li>
<li><a class="book" href="/user/book">My Book</a></li>
</ul>
$(document).ready(function () {
var page = document.location.href.split('/').slice(-1)[0];
$('.menu .' + page).addClass('selected');
});
You can grab the part you want with regex:
var userPage = /user\/(.+)/.exec(location.href)[1];
That will give you the part after user/. Then you could use a switch statement:
switch (userPage) {
case 'profile':
...
break;
case 'book':
...
break;
}
You would want to switch off of location.pathname. Granted that you give that <ul> a class of nav:
$(function () {
if (location.pathname.search("/user/profile") != -1) {
// page is /user/profile
$("#nav li").eq(0).addClass("selected");
} else if (location.pathname.search("/user/photos") != -1) {
// page is some/thing
$("#nav li").eq(3).addClass("selected");
}
... etc
});
Things to notice
We use $(function () {...}); as opposed to $(document).ready(function() {...});. It is less typing and more efficient
We use String.search(), which returns the index at which the string "/user/profile" appears. If the string is not found, String.search() will return -1, so if it != -1, it exists.
We also use jQuery.eq( index ) this treats elements selected by a jQuery selector as an array and returns the element of the specified index.
References
Check out jQuery's .eq here, and JavaScript's String.search here

Categories