Add and remove class to nav after page reload - javascript

I have a navigation which can have up to two sub menus. Means, I have to open the li above (add class "open" to class "arrow") two times if the current page is a href in a sub sub navigation.
However, I am struggling on how to do this, how to solve this problem. My idea was to solve it via jQuery. Is there a better solution?
This is my navigation:
<ul class="page-sidebar-menu page-header-fixed page-sidebar-menu-light">
<li class="nav-item start">
<a href="my-domain.com/dashboard" class="nav-link nav-toggle">
<i class="icon-home"></i>
<span class="title">Dashboard</span>
<span class="selected"></span>
</a>
</li>
<li class="nav-item">
<a href="javascript:void(0)" class="nav-link nav-toggle">
<i class="icon-people"></i>
<span class="title">Kontakte</span>
<span class="arrow"></span>
</a>
<ul class="sub-menu">
<li class="nav-item">
<a href="my-domain.com/kontaktverwaltung" class="nav-link ">
<span class="title">Kontaktverwaltung</span>
<span class="selected"></span>
</a>
</li>
<li class="nav-item">
<a href="javascript:void(0)" class="nav-link nav-toggle">
<span class="title">Kunden</span>
<span class="arrow"></span>
</a>
<ul class="sub-menu">
<li class="nav-item ">
Kundendetails
<span class="selected"></span>
</li>
<li class="nav-item">
Kundenverwaltung
<span class="selected"></span>
</li>
</ul>
</li>
</ul>
</li>
</ul>
Example:
The current page is this one: my-domain.com/kundenverwaltung. That means, I have to add the class "active open" to both li elements of the ul sub menus as well as the class "open" to the class "arrow" of the li elements.
This is how it should be:
<ul class="page-sidebar-menu page-header-fixed page-sidebar-menu-light">
<li class="nav-item start">
<a href="my-domain.com/dashboard" class="nav-link nav-toggle">
<i class="icon-home"></i>
<span class="title">Dashboard</span>
</a>
</li>
<li class="nav-item **active open**">
<a href="javascript:void(0)" class="nav-link nav-toggle">
<i class="icon-people"></i>
<span class="title">Kontakte</span>
<span class="arrow **open**"></span>
</a>
<ul class="sub-menu">
<li class="nav-item">
<a href="my-domain.com/kontaktverwaltung" class="nav-link ">
<span class="title">Kontaktverwaltung</span>
</a>
</li>
<li class="nav-item **active open**">
<a href="javascript:void(0)" class="nav-link nav-toggle">
<span class="title">Kunden</span>
<span class="arrow **open**"></span>
</a>
<ul class="sub-menu">
<li class="nav-item ">
Kundendetails
</li>
<li class="nav-item">
Kundenverwaltung
</li>
</ul>
</li>
</ul>
</li>
</ul>
I have marked the changes on the classes with ** before and after the class name. This is my jQuery so far:
<script>
$("a.nav-link").each(function(index){
if($(this).attr("href") == window.location.href) {
$(this).parent().addClass("active open");
if ($(this).parent().parent().is("ul")) {
$(this).parent().parent().parent().addClass("active open");
var li = $(this).parent().parent().parent();
$(li[0].nodeName + " .arrow").addClass("open");
}
}
});
</script>
However, I don't think this is the best solution.. is there any better way? Kind regards

If you change the structure of HTML, your code will not be work, so - don't use parent(), try to use closest() https://api.jquery.com/closest, by reason that the closest() is a more reliable method
Cache data. U can use
http://api.jquery.com/attribute-equals-selector:
var $a = jQuery('a[href*="' + window.location.href + '"]');
$a.addClass("active open");
For adding a class to active page you should try added this by backend side, different kind of templating - can do it. But your approach also can be use

Related

Nav bar get Active for two items

in my web project, I used a free theme https://themewagon.com/themes/free-bootstrap-4-html-5-admin-dashboard-website-template-skydash/
Here in the nav bar, I customized it as
<nav class="sidebar sidebar-offcanvas" id="sidebar">
<ul class="nav">
<li class="nav-item">
<a class="nav-link elements" href="~/Home/Index">
<i class="icon-grid menu-icon"></i>
<span class="menu-title">Dashboard</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#Url.Action("Index","SelfService")">
<i class="ti-menu-alt menu-icon"></i>
<span class="menu-title">Our Services</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#Url.Action("OnProcessTasks","SelfCareTasks")">
<i class="ti-timer menu-icon"></i>
<span class="menu-title">In Process Tasks</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#Url.Action("CompletedTasks","SelfCareTasks")">
<i class="ti-file menu-icon"></i>
<span class="menu-title">Completed Tasks</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#Url.Action("OnProcessTasks","SelfCareTasks")">
<i class="ti-face-smile menu-icon"></i>
<span class="menu-title">My Profile</span>
</a>
</li>
</ul>
</nav>
My issue is When I run this, on load first 2 items showed as Active and both items are highlighted. I checked with the sample, but it runs without this issue, also I tried removing the href and then the nav bar showed only one item as active.
I still couldn't figure out why this happening. Any comments?
I can't see what is wrong other than just this thing:
<a class="nav-link elements" href="~/Home/Index">
Change it to:
<a class="nav-link elements" href="#Url.Action("Index", "Home")">
The reason for this change is because you're following the Razor Syntax.

How can I go to href on tag with hide attribute value?

How can I go to href on tag with hide attribute value?
here is my navigation bar
$(function() {
$('#p10').hide();
$('#p11').hide();
$('#p12').hide();
$('#p13').hide();
$('#p14').hide();
$('#p15').hide();
$('#p16').hide();
$('#p17').hide();
$('#p18').hide();
$('#p19').hide();
$('#p20').hide();
$('#p21').hide();
$('#hideshow').click(function() {
$('#p10').toggle();
$('#p11').toggle();
$('#p12').toggle();
$('#p13').toggle();
$('#p14').toggle();
$('#p15').toggle();
$('#p16').toggle();
$('#p17').toggle();
$('#p18').toggle();
$('#p19').toggle();
$('#p20').toggle();
$('#p21').toggle();
});
$('#navbarNav').click(function() {
console.log($(this));
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item active">
<a class="nav-link " href="#section2">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#p1">Subway congestion prediction app</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#p2">Image classification</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#p3">Community site</a>
</li>
...
<li class="nav-item">
<a class="nav-link" href="#p17">Assembly</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#p18">Data structure</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#p19">Concave</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#p20">Contact</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#section5">Contact</a>
</li>
</ul>
</div>
When loading the page here, p10 to p21 are hidden.
In this situation, if you click from 10 to 21 of the navigation bar, it is hidden and you cannot move to href.
How can I remove the hide attribute when clicking p10 to p21 of the navigation bar (click the #hideshow button at the time of the hide attribute) and move to p10 to p21?
<button type="button" class="btn btn-dark btn-lg " style="font-size:3rem; margin-bottom:100px; background-color:#3e454e" id="hideshow">Want to see more?</button>
#showhide button is between #p9 #p10
The jquery-selector is used in this way:
$('#<id>').hide();
-> the <id> (after the #) must be the id of the element. In your HTML it is the given href.
In your given code the #hideshow button is missing.
You try to select with jQuery IDs (10 - 21) but the HTML doesn't contain these IDs. Furthermore: The click event listener is assigned to the button #hideshow which doesn't exist.
If you define the IDs and add the button #hideshow it works:
$(function() {
$('#p10').hide();
$('#p11').hide();
$('#p12').hide();
$('#p13').hide();
$('#p14').hide();
$('#p15').hide();
$('#p16').hide();
$('#p17').hide();
$('#p18').hide();
$('#p19').hide();
$('#p20').hide();
$('#p21').hide();
$('#hideshow').click(function() {
$('#p10').toggle();
$('#p11').toggle();
$('#p12').toggle();
$('#p13').toggle();
$('#p14').toggle();
$('#p15').toggle();
$('#p16').toggle();
$('#p17').toggle();
$('#p18').toggle();
$('#p19').toggle();
$('#p20').toggle();
$('#p21').toggle();
});
$('#navbarNav').click(function() {
console.log($(this));
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item active">
<a class="nav-link " href="#section2">Home</a>
</li>
<li id="1p17" class="nav-item">
<a class="nav-link" href="#p1">Subway congestion prediction app</a>
</li>
<li id="p2" class="nav-item">
<a class="nav-link" href="#p2">Image classification</a>
</li>
<li id="p3" class="nav-item">
<a class="nav-link" href="#p3">Community site</a>
</li>
...
<button type="button" id="hideshow">Want to see more?</button>
...
<li id="p17" class="nav-item">
<a class="nav-link" href="#p17">Assembly</a>
</li>
<li id="p18" class="nav-item">
<a class="nav-link" href="#p18">Data structure</a>
</li>
<li id="p19" class="nav-item">
<a class="nav-link" href="#p19">Concave</a>
</li>
<li id="p20" class="nav-item">
<a class="nav-link" href="#p20">Contract</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#section5">Contact</a>
</li>
</ul>
</div>

How to set active class on current nav item

I am facing problem while setting active class on nav item.
Here is my code on template
<nav class="mt-2">
<ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">
<li class="nav-item">
<a href="{{ url('/dashboard') }}" class="nav-link">
<i class="nav-icon fas fa-tachometer-alt"></i>
<p>
Dashboard
</p>
</a>
</li>
<li class="nav-item">
<a href="{{ url('/dashboard/logo') }}" class="nav-link">
<i class="nav-icon fab fa-bandcamp"></i>
<p>
Add/Change Logo
</p>
</a>
</li>
<li class="nav-item has-treeview">
<a href="#" class="nav-link">
<i class="nav-icon fas fa-image"></i>
<p>
Banner
<i class="fas fa-angle-left right"></i>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="{{ url('/dashboard/banner') }}" class="nav-link">
<i class="nav-icon fas fa-plus"></i>
<p>Add Banner</p>
</a>
</li>
<li class="nav-item">
<a href="{{url('/dashboard/banner/edit')}}" class="nav-link">
<i class="nav-icon fas fa-edit"></i>
<p>Edit Banner</p>
</a>
</li>
</ul>
</li>
</ul>
</nav>
I tried
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
var url = window.location;
$('ul.nav li.nav-item a[href="' + url + '"]').parent().addClass('active');
$('ul.nav li.nav-item a').filter(function () {
return this.href == url;
}).parent().addClass('active').parent().parent().addClass('active');
});
</script>
But this code setting the "active" class on list tag but not in anchor tag.
Instead of using .parent(), try using .closest('a').
closest() will traverse UP the DOM tree until it finds the specified selector - in the above example, the first <a> tag above the element.
Virtually all of your .parent() can be replaced with .closest() - but use as desired. There is no "right" or "wrong", just what works or is easiest for you.
You can use any normal css/jQuery selector with closest() - from a tagName:
.closest('a')
to a className:
.closest('a.nav-item')
etc.
Reference:
https://api.jquery.com/closest/

Storing active class in local storage when using bootstrap 4 tabs

I am having some trouble with the tab list below:
<ul class="nav nav-tabs" data-tabs="tabs" role="tablist">
<li class="nav-item">
<a class="nav-link active" href="{$PageUrl}" role="tab">View</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{$PageUrl}?action=edit" role="tab">Edit</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{$PageUrl}?action=diff" role="tab">History</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{$PageUrl}?action=print" role="tab">Print</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{$PageUrl}?action=attr" role="tab">Attributes</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="dropdown2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown</a>
<div class="dropdown-menu" aria-labelledby="dropdown2">
<a class="dropdown-item" data-toggle="tab" href="#fat2" role="tab">#fat</a>
<a class="dropdown-item" data-toggle="tab" href="#mdo2" role="tab">#mdo</a>
</div>
</li>
</ul>
Everything displays fine but this differs from how a lot of people implement tabs. Most examples i see have 'tab-content' and that shows the content for each tab. In my case i am using tabs to link alternate pages all together. This is where my issue comes in, When clicking on 'Edit' tab it does indeed load the edit page but with the active class or the 'View' tab still active. I cannot get the active class to switch between the tabs. I think this is because the page is reloading therefore eliminating the active data and setting it to default. How can I get around this and have it show the correct active tab after the newly selected page loads? Thanks for any help!
Edit:
Previously I was trying to use this at the bottom of my body with no luck:
$(function(){
var current = location.pathname;
$('#nav li a').each(function(){
var $this = $(this);
// if the current path is like this link, make it active
if($this.attr('href').indexOf(current) !== -1){
$this.addClass('active');
}
})
})
Here is a possible solution:
<ul class="nav nav-tabs" data-tabs="tabs" role="tablist">
<li class="nav-item">
<a class="default nav-link" href="{$PageUrl}" role="tab">View</a>
</li>
<li class="nav-item">
<a class="edit nav-link" href="{$PageUrl}?action=edit" role="tab">Edit</a>
</li>
<li class="nav-item">
<a class="diff nav-link" href="{$PageUrl}?action=diff" role="tab">History</a>
</li>
<li class="nav-item">
<a class="print nav-link" href="{$PageUrl}?action=print" role="tab">Print</a>
</li>
<li class="nav-item">
<a class="attr nav-link" href="{$PageUrl}?action=attr" role="tab">Attributes</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="dropdown2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown</a>
<div class="dropdown-menu" aria-labelledby="dropdown2">
<a class="dropdown-item" data-toggle="tab" href="#fat2" role="tab">#fat</a>
<a class="dropdown-item" data-toggle="tab" href="#mdo2" role="tab">#mdo</a>
</div>
</li>
</ul>
<script>
$(function() {
var action = (location.search.match(/(\^?|&)action=(.*?)($|&)/i) || [])[2]
if(action) {
$('a.nav-link.'+action).addClass('active')
} else {
$('a.nav-link.default').addClass('active')
}
})
</script>
Does not add active class to any of the tabs by default.
All tab links have their action as class, to make it easy
On load it thecks the query in the window's address, and sets the active class accordingly

Set class to active on additional li elements upon navbar click

I have the following side bar menu code. Upon click on any of the nav items it highlights / makes the class active.
$(document).ready(function() {
$(".nav li").click(function() {
if ($(".nav li").removeClass("active")) {
$(this).removeClass("active");
}
$(this).addClass("active");
});
});
<ul class="nav">
<li class="nav-item">
<a data-target="#system-settings" data-toggle="pill" class="nav-link" href="#system-settings" id="system-settings">System Settings</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#hosts" id="hosts" data-parent="#hosts">Hosts</a>
</li>
<li class="nav-item ">
<a class="nav-link" href="#card-range" id="card-range">Cards</a>
</li>
<li class="nav-item">
<a class="nav-link" id="pinpads" href="#pinpads">Printer</a>
</li>
<li class="nav-item">
<a class="nav-link" id="xmls" href="#xmls">Pinpad</a>
</li>
</ul>
Now I have similar items at the top of the page presented as a connected circle:
<div class="connected-line">
<ul>
<li class="active">1
<p> System </p>
</li>
<li id="hosts">2
<p> Hosts </p>
</li>
<li>3
<p> Cards </p>
</li>
<li>4
<p> Devices </p>
</li>
</ul>
</div>
See jsfiddle:
https://jsfiddle.net/vk3qw09f/345/
Now if the user clicks on the side bar menu, it should also set corresponding class as active on the "connected-line" list elements.
For eg: Cliking on navbar "System Settings" should also add a class 'active' to the li item inside the circled li "System"
I know it's not recommednded to have the same 2 ids on the same page. So looking for a smarter way to achieve this.
EDIT: my current code will only make that class active: $(this).addClass("active");
I probably want to make all classes that share the same name active
I assume this is what you're looking for.
$(document).ready(function() {
$(".nav li a").click(function(e) {
e.preventDefault();
$(".nav li").removeClass("active");
$(".connected-line li").removeClass("active");
$($(this).attr('href')).addClass('active');
$(this).addClass("active");
});
});
Full working snippet here. Haven't added snippet in answer because:
a) SO doesn't yet support SCSS,
b) i'm lazy.
Also note I made minor mods to your CSS and markup. Another note: duplicate ids are illegal in HTML. You have them? Expect your JavaScript to break. It's as simple as that.
Replace the code in your code. I hope, you can do it. Let me know, If any problem.
$(document).ready(function() {
$(".nav li a").click(function() {
$(".connected-line ul li").removeClass("active");
id = $(this).prop('id');
$("#" + id).addClass("active")
});
});
<div class="connected-line">
<ul>
<li class="active" id="system-settings">1
<p> System </p>
</li>
<li id="hosts">2
<p> Hosts </p>
</li>
<li id="card-range">3
<p> Cards </p>
</li>
<li id="pinpads">4
<p> Devices </p>
</li>
<li id="xmls" >5
<p> Lanes </p>
</li>
</ul>
</div>
<ul class="nav">
<li class="nav-item">
<a data-target="#system-settings" data-toggle="pill" class="nav-link" href="#system-settings" id="system-settings">System Settings</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#hosts" id="hosts" data-parent="#hosts">Hosts</a>
</li>
<li class="nav-item ">
<a class="nav-link" href="#card-range" id="card-range">Cards</a>
</li>
<li class="nav-item">
<a class="nav-link" id="pinpads" href="#pinpads">Printer</a>
</li>
<li class="nav-item">
<a class="nav-link" id="xmls" href="#xmls">Pinpad</a>
</li>
</ul>
It is best not you have two elements with the same id attribute. This is because native functions such as getElementById will never be able to select the second instance of the element with that id.
That being said to get your demo to work I changed the js to use classes instead of ids on the second set of elements. This can be achieved in many other ways as well:
$(document).ready(function() {
$(".nav li").click(function() {
$('li').removeClass("active");
$(this).removeClass("active");
$(this).addClass("active");
const clickedId = $(this).children()[0].id;
$(`.${clickedId}`).addClass('active');
});
});
and then in the html
<div class="connected-line">
<ul>
<li class="system-settings">1
<p> System </p>
</li>
<li class="hosts">2
<p> Hosts </p>
</li>
<li class="card-range">3
<p> Cards </p>
</li>
<li class="pinpads">4
<p> Devices </p>
</li>
<li class="xmls">5
<p> Lanes </p>
</li>
</ul>
</div>
<ul class="nav">
<li class="nav-item">
<a data-target="#system-settings" data-toggle="pill" class="nav-link" href="#system-settings" id="system-settings">System Settings</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#hosts" id="hosts" data-parent="#hosts">Hosts</a>
</li>
<li class="nav-item ">
<a class="nav-link" href="#card-range" id="card-range">Cards</a>
</li>
<li class="nav-item">
<a class="nav-link" id="pinpads" href="#pinpads">Printer</a>
</li>
<li class="nav-item">
<a class="nav-link" id="xmls" href="#xmls">Pinpad</a>
</li>
</ul>
Rewrite the html code as follows
<div class="connected-line">
<ul>
<li class="system active">1
<p> System </p>
</li>
<li class="host" id="hosts">2
<p> Hosts </p>
</li>
<li class="card">3
<p> Cards </p>
</li>
<li class="device">4
<p> Devices </p>
</li>
<li class="lane">5
<p> Lanes </p>
</li>
</ul>
</div>
<ul class="nav">
<li class="nav-item system">
<a data-target="#system-settings" data-toggle="pill" class="nav-link" href="#system-settings" id="system-settings">System Settings</a>
</li>
<li class="nav-item host">
<a class="nav-link" href="#hosts" id="hosts" data-parent="#hosts">Hosts</a>
</li>
<li class="nav-item card">
<a class="nav-link" href="#card-range" id="card-range">Cards</a>
</li>
<li class="nav-item printer">
<a class="nav-link" id="pinpads" href="#pinpads">Printer</a>
</li>
<li class="nav-item pinpad">
<a class="nav-link" id="xmls" href="#xmls">Pinpad</a>
</li>
</ul>
Make sure to add same class name to matching li. Then modify the js code as follows,
$(document).ready(function() {
$(".nav li").click(function() {
//Make sure to add class name immediately after "nav-item". For eg."nav-item printer"
var calss=$(this).attr('class').split(' ')[1];
console.log(calss);
$(".nav li").removeClass("active");
$(".connected-line ul li").removeClass("active");
$("li." + calss).addClass("active");
});
});

Categories