I have this one problem regarding the highlighted navbar menu which will only highlight when we clicked on it. For that to work, I'm using javascript. However, each pages has its own sub pages, for example, page Home has a link of local/home, but its content will lead to local/home/content. The sub link will not make the navbar to function The navbar was coded in different file, which I just extends in the home and other pages. I'm not very good at explaining but if I can elaborate more on any part I would do so. Below I attached my JS and my navbar:
HTML :
<ul class="navbar-nav mr-auto" id="nav">
<li class="nav-item">
<a class="nav-link active" href="{{ url('/') }}">Home
<span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('courses') }}">opportunities</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('events') }}">events</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('uqalc') }}">courses</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('contact') }}">contact</a>
</li>
</ul>
JS :
const currloc = location.href;
const menuItem = document.querySelectorAll('a');
const menuLen = menuItem.length;
for (let i = 0; i < menuLen; i++) {
menuItem[i].classList.remove('active');
if (menuItem[i].href === currloc) {
menuItem[i].className = "nav-link active";
}
}
From what I read from your question, you want the navbar to change color when clicked. This can be easily accomplished in two different ways.
The first is making a #Active id that would be given to the proper navbar link on every page. (More here)
The second is if you are staying on the same page but still want the button to change color when clicked. (More here)
Either way is effective.
Have questions? Comment download below. Like my answer? Give me a checkmark and up-vote.
Related
I looked for similar posts but they all seem to resort to Jquery, which by now is considered outdated in most cases.
My question is:
How can I change the class of active (currently on my "Projects" labeled tag, to the siblings when clicking it?
I'm really trying to achieve results with only Vanilla Javascript and hopefully a .forEach method, to make it more functional.
Sorry for not providing any JS at this moment, it seems I'm really struggling with the basics .
<nav id="sidebar">
<div class="toggle-btn" onclick="toggleSidebar()">
<i class="fas fa-angle-double-right fa-2x"></i>
</div>
<ul class="navbar-nav">
<li class="nav-item">
PROJECTS
</li>
<li class="nav-item">
CREATION PROCESS
</li>
<li class="nav-item">
BEFORE AND AFTER
</li>
<li class="nav-item">
ABOUT THE STUDIO
</li>
<li class="nav-item">
CONTACT
</li>
</ul>
</nav>
EDIT:
Thanks to the first reply, I managed to figure out a clean and modern way to refactor it to my taste:
const tabs = document.querySelectorAll('.nav-link');
tabs.forEach(tab => tab.addEventListener('click', toggleActiveTab));
function toggleActiveTab(e) {
tabs.forEach(tab => {
tab.classList.remove('active');
});
e.currentTarget.classList.toggle('active');
}
Here you go with a solution
var items = document.getElementsByClassName('nav-link');
for (var i = 0; i < items.length; i++) {
items[i].addEventListener('click', printDetails);
}
function printDetails(e) {
for (var i = 0; i < items.length; i++) {
if (items[i].classList.contains("active")) {
items[i].classList.toggle("active")
}
}
this.classList.add("active");
}
.active {
background: #ddd;
}
<nav id="sidebar">
<div class="toggle-btn" onclick="toggleSidebar()">
<i class="fas fa-angle-double-right fa-2x"></i>
</div>
<ul class="navbar-nav">
<li class="nav-item">
PROJECTS
</li>
<li class="nav-item">
CREATION PROCESS
</li>
<li class="nav-item">
BEFORE AND AFTER
</li>
<li class="nav-item">
ABOUT THE STUDIO
</li>
<li class="nav-item">
CONTACT
</li>
</ul>
</nav>
Add an event listener to each nav-link if you can't add onClick event to HTML code.
Then in the click method check for active class in each nav-link element, if active class is present then toggle it.
Then add active class to the clicked tab.
It looks ridiculous to do so many tasks on a button click while every button should have its own events:
function allStories() {
$('#zero-md').hide();
$('.container-aboutme').hide();
$('.container-allstories').show();
$('.container-allstories').load("pages/allstories.html");
$("#home").removeClass("nav-link active").addClass("nav-link");
$("#aboutme").removeClass("nav-link active").addClass("nav-link");
$("#allposts").removeClass("nav-link").addClass("nav-link active");
}
function aboutMe() {
$('#zero-md').hide();
$('.container-allstories').hide();
$('.container-aboutme').show();
$('.container-aboutme').load("pages/about.html");
$("#home").removeClass("nav-link active").addClass("nav-link");
$("#allposts").removeClass("nav-link active").addClass("nav-link");
$("#aboutme").removeClass("nav-link").addClass("nav-link active");
}
<li class="nav-item">
<a class="nav-link" id="allposts" onclick="allStories()" href="#">All posts</a>
</li>
<li class="nav-item">
<a class="nav-link" id="aboutme" onclick="aboutMe()" href="#">About me</a>
</li>
Is there is a better, more effective way to organize such events with less code?
You mean this
$("#nav").on("click",".nav-link",function(e) {
e.preventDefault(); // stop the link
const id = this.id;
const $thisContainer = $('.container'+id);
$('#zero-md').hide();
$('.container').hide(); // hide all containers
$thisContainer.load("pages/"+id+".html",function() { // perhaps not load if already loaded
$thisContainer.fadeIn("slow");
}) ;
$(".nav-link").removeClass("active")
$(this).addClass("active")
})
<ul id="nav">
<li class="nav-item">
<a class="nav-link" id="allposts" href="#">All posts</a>
</li>
<li class="nav-item">
<a class="nav-link" id="about" href="#">About me</a>
</li>
</ul>
Yes. Try to keep your code DRY (don't repeat yourself.)
Add an event listener in your JS.
Use e.target to determine what was clicked.
Chain your commands together when they're operating on the same elements.
Don't remove a class and then add the same class back. Just remove the one you want to get rid of.
I've added some stand in elements since not everything was present in your HTML.
$('.nav-link').click( (e)=>{
let theLink = $(e.target).attr('id');
const container = '.container-'+$(theLink).attr('id');
$('#zero-md').hide();
$('.container').hide();
$(container).show().load("pages/"+theLink+".html");
alert('loading: pages/'+theLink+'.html');
$("#home").removeClass("nav-link active").addClass("nav-link");
$(".nav-link").removeClass("active");
$("#"+theLink).addClass("active");
});
.active {
font-size: 1.5rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<li class="nav-item">
<a class="nav-link" id="allstories" href="#">All posts</a>
</li>
<li class="nav-item">
<a class="nav-link" id="aboutme" href="#">About me</a>
</li>
<div class="container container-allstories">All Stories</div>
<div class="container container-aboutme">About Me</div>
<div id="zero-md">Zero MD</div>
Using bootstrap 4 and asp.net core for a personal project I've been tinkering with for the past couple of months. I've got a navbar in my _Layout that is shared across my entire site. I've also got some css that styles the navbar link text.
I'm trying to change the active class on the links so the currently-visited controller is highlighted with a different color. I'm using js to do this. The color is changing initially, so I'm sure that the js is adding the active class to the new link and removing it from the previous active link, but when the page finishes loading, they reset and the active class goes back to Home.
Here is my navbar in _Layout.cshtml:
<nav class="navbar navbar-toggleable-md navbar-inverse bg-inverse">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarToggler" aria-controls="navbarToggler" aria-expanded="false" aria-label="Toggle navigation">
<img src="~/images/logo1.png" width="40" height="40" alt="" />
</button>
<div class="collapse navbar-collapse" id="navbarToggler">
<ul class="nav navbar-nav mr-auto mt-2 mt-lg-0">
<li class="nav-item active">
<a class="nav-link" asp-action="Index" asp-controller="Home">Home<span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" asp-action="Index" asp-controller="aaaa">Aaaa</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-action="Index" asp-controller="bbbb">Bbbb</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-action="Index" asp-controller="cccc">Cccc</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-action="Index" asp-controller="dddd">Dddd</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<button class="btn btn-outline-danger btn-sm"
type="submit" asp-action="Login" asp-controller="Account">
Login
</button>
</form>
</div>
Here is the js that I'm declaring in the #scripts section of _Layout:
$( '.navbar-inverse .navbar-nav a' ).on( 'click', function () {
$( '.navbar-inverse .navbar-nav' ).find( 'li.active' ).removeClass( 'active' );
$( this ).parent( 'li' ).addClass( 'active' );
});
And my css:
.navbar-inverse .navbar-nav .open > .nav-link,
.navbar-inverse .navbar-nav .active > .nav-link,
.navbar-inverse .navbar-nav .nav-link.open,
.navbar-inverse .navbar-nav .nav-link.active {
color: yellow;
}
Why is the active link being reset when the new page loads? I know the js is working because while the page is loading, "Home" is not yellow anymore, but the new link I clicked in the navbar is yellow. But when the loading is complete, the yellow goes back to Home. Any insights would be appreciated, I'm rather new at software development.
You're setting active on click. However, when the browser actually goes to that URL following the click, a completely different view is rendered. Therefore, there's no concept of anything having been set a certain way or done previously.
Instead, you need to either have your JS run onload, or simply just send the HTML with the correct item active in the first place, and throw away the JS. The easiest way to do that is something like:
#{ string url; }
Then for each nav link:
#{ url = Url.Action("Foo", "Bar"); }
<li class="#(Request.Path.StartsWith(url) ? "active" : null)">
Foo
</li>
Setting the url variable is mostly just a way to not repeat yourself with the action/controller for the link, since you need the link URL in two different places.
The meat is in the ternary. If the current URL path starts with this link's URL (which should cover both the scenario of being equal to and just being a parent of the current URL), then you apply the active class.
EDIT
Because of using StartsWith, a link for "Home" will basically always be set as active, since every URL would start with /. You probably want to make an exception on that link and instead just do:
#{ url = Url.Action("Index", "Home"); }
<li class="#(Request.Path == url ? "active" : null)">
Home
</li>
Then, that link will only be marked active if the URL is actually /.
Thanks to #Chris Pratt for his guidance. I got this working albeit with a couple of changes, possibly due to me changing my mind on the navbar and moving to a tabbed navbar (like Twitter's mobile app uses). Here's my navbar code in _Layout.cshtml:
<!--navbar-->
#{ string url; }
<ul class="nav navbar-dark bg-dark nav-tabs nav-fill">
#{ url = Url.Action("Index", "Home"); }
<li class="nav-item">
<a class="nav-link #(Context.Request.Path == url ? "active" : null)" href="#url">Home</a>
</li>
#{ url = Url.Action("Index", "Spells"); }
<li class="nav-item">
<a class="nav-link #(Context.Request.Path.StartsWithSegments(url) ? "active" : null)" href="#url">Spells</a>
</li>
#{ url = Url.Action("Index", "Crits"); }
<li class="nav-item">
<a class="nav-link #(Context.Request.Path.StartsWithSegments(url) ? "active" : null)" href="#url">Crits</a>
</li>
#{ url = Url.Action("Index", "Journal"); }
<li class="nav-item">
<a class="nav-link #(Context.Request.Path.StartsWithSegments(url) ? "active" : null)" href="#url">Journal</a>
</li>
</ul>
Now that the active class switching is working as expected, I can add some styling, and replace the text with icons that I'll make.
Gave you an upvote, Chris Pratt, but my rep is too low to show it publicly for now. Thanks again.
I have a Sidebar / Menu that I am working with. It has been created with Bootstrap, DJango, and Javascript.
Basically, I am trying to write Javascript so that when on clicks on a menu-item, the background changes color (dark blue), the icon change color (light green / turquoise) and it gets a type of "wedge"
Below is an example of a menu-item that has been chosen (Dashboard) along with menu-items that have not been chosen (Security and Messages). The "wedge" has a red arrow pointing to it.
Here is the HTML code that is being used:
[... snip ...]
<div class="page-container">
<div class="page-sidebar-wrapper">
<div class="page-sidebar navbar-collapse collapse">
<ul class="page-sidebar-menu page-header-fixed page-sidebar-menu-hover-submenu "
data-keep-expanded="false" data-auto-scroll="true" data-slide-speed="200">
<li class="nav-item start active open">
<a href="{% url 'mainadmin:dashboard' %}" class="nav-link nav-toggle">
<i class="fa fa-tachometer"></i>
<span class="title">Dashboard</span>
<span class="selected"></span>
<span class="arrow open"></span>
</a>
</li>
<li class="nav-item ">
<a href="{% url 'mainadmin:security' %}" class="nav-link nav-toggle">
<i class="fa fa-users"></i>
<span class="title">Security</span>
<span class="arrow"></span>
</a>
</li>
<li class="nav-item ">
<a href="{% url 'mainadmin:in_progress' %}" class="nav-link nav-toggle">
<i class="fa fa-comment"></i>
<span class="title">Messages</span>
<span class="arrow"></span>
</a>
<ul class="sub-menu">
<li class="nav-item ">
<a href="{% url 'mainadmin:in_progress' %}" class="nav-link ">
<span class="title">List All Messages</span>
</a>
</li>
<li class="nav-item ">
<a href="{% url 'mainadmin:in_progress' %}" class="nav-link ">
<span class="title">List My Messages</span>
<span class="badge badge-danger"></span>
</a>
</li>
</ul>
</li>
[... snip ...]
Here is the Javascript code:
<script>
$(document).ready(function () {
$('.nav-item a').click(function(e) {
$('.nav-item a').removeClass('selected');
$('.nav-item a').removeClass('arrow');
$('.nav-item a').removeClass('open');
$('.nav-item a').removeClass('active');
alert("I have gotten in");
var $parent = $(this).parent();
$parent.addClass('selected');
$parent.addClass('arrow');
$parent.addClass('open');
$parent.addClass('active');
e.preventDefault();
});
});
</script>
I do get the alert message - but - what happens is :
-> the background of the chosen menu-item does change color - which is correct
--> The icon of the chosen menu-item changes color (to light blue / turquoise) - which is correct
-> the tick of the arrow does not take place for the chosen menu-item :(
-> the old chosen menu item does not "de-select"
What am I doing wrong?
TIA
Hi #Joe Lissner
Thanks so much for the response!
I had to add the following to get the "wedge" portion to work. It required span tags
// REFERENCE: https://stackoverflow.com/questions/2013710/add-span-tag-within-anchor-in-jquery
$(this).append('<span class="selected"></span>');
$(this).append('<span class="arrow open"></span>');
While this works when clicking on the main-menu item, I'm not so lucky when it comes to clicking on sub-menu items. As of now, I am pretty much new to Javascript.
How would one get the sub-menu items to work?
Also, when clicking on an item, it does not go to the page specified in "href="
How would can one make changes to the code so that when the menu-item is clicked, it would go to the page specified in "href="
Again, thanks for the response :-)
You are removing the classes from the a tags, not the .nav-item elements.
Try this:
$(document).ready(function () {
$('.nav-item a').click(function(e) {
e.preventDefault(); // best practice to have this first, if you remove this line then the link will function as expected.
var $parent = $(this).parent();
var $arrow = $parent.find('.arrow');
$('.nav-item').removeClass('selected arrow open active'); // simplified
$('.nav-item .arrow').removeClass('open');
$('.nav-item .selected').detach(); // remove the span that was there before
alert("I have gotten in");
$parent.addClass('open active'); // simplified
$arrow.addClass('open').before('<span class="selected" />')
});
});
Edit - Fixed the issue with the arrow
I have following code for nav-pills component:
<ul id="steps" class="nav nav-pills form-steps">
<li class="active"><a data-toggle="pill" href="#options"></a></li>
<li><a data-toggle="pill" href="#payments"></a></li>
</ul>
This is how the look of active a is made (basically it's just a circle filled with special color):
.form-steps > li.active > a {
background-color: #931f2a;
}
And here's code for a regular a:
.promoter-form-steps > li > a {
border: 2px solid #931f2at;
height: 30px;
width: 30px;
border-radius: 100%;
}
I suppose that by adding .active class to corresponding li element makes a element filled with color, but it doesn't when I open modal where this component is placed for the fist time. When I open modal for the second time after I click on another link, I see correct behavior, i.e .active class is filled with color. It's an SPA and I have another nav-pills like this with exact markup and it works just fine and I don't quite understand why this behavior doesn't work on second nav-pills. I double checked that class names and ids don't repeat each others and I am sure that no custom js was involved into this.
Can you please give me a direction to inspect what I did wrong? Thanks in advance!
Here's the recommended format as determined by Twitter Docs:
<ul class="nav nav-pills">
<li class="nav-item">
<a class="nav-link active" href="#">Active</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#">Disabled</a>
</li>
</ul>
Your list tags need to have a class of nav-item and your anchors need a class of nav-link before it can use the active class