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.
Related
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.
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>
So instead of adding an active class to the navbar using HTML I instead wanted to add it through jQuery but my code doesn't seem to work.
$('.navbar-nav li a[href="' + location.pathname + '"]').addClass('active');
<nav>
<ul class="navbar-nav">
<li class="nav-item" >
<a class="nav-link active" href="">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="">Wat is het?</a>
</li>
</ul>
</nav>
Can anybody help me out?
I think what do you need is window.location.href.
Something like this:
var pathname = window.location.href;
$('.navbar-nav li a').attr('href',pathname).addClass('active');
Check this example: https://jsfiddle.net/tbx56gtL/7/
Maybe you can do it like this:
$(function() {
var currentLoc = window.location.href;
if(/PageYouWant/.test(currentLoc) {
$('.navbar-nav li a').addClass('active');
}
});
If you want to set active in anchor tag you can do one of the following options.
Asign ids to every a tag
Asign a data attrib and add a class toggleClassX
Use $(this).addClass("active")
The following are the examples of each recomendation :
1 html:
<nav>
<ul class="navbar-nav">
<li class="nav-item" >
<a class="nav-link active" id="myId1" href="">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" id="myId2" href="">Wat is het?</a>
</li>
</ul>
</nav>
2 html:
<nav>
<ul class="navbar-nav">
<li class="nav-item" >
<a class="nav-link toggleClass1 active" data-tclass="1" href="">Home</a>
</li>
<li class="nav-item">
<a class="nav-link toggleClass2" data-tclass="2" href="">Wat is het?</a>
</li>
</ul>
</nav>
3 html: your structure is ok for the last example
1 js:
$("element").click(function(){
$("#myId1").addClass("active")
});
2 js:
$(".nav-link").click(function(){
var tclass = $(this).data("tclass)
$(".toggleClass"+tclass).addClass("active")
});
3 js:
$(".nav-link").click(function(){
$(this).addClass("active")
});
Hope the above answer your question.
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
<nav id="navMenu" class="navMenu">
<ul>
<li class="active homePage">
Home
</li>
<li class="resourcesPage">
Resources
<ul>
<li><span class="icon elem0"></span>Restaurants</li>
<li><span class="icon elem0"></span>Businesses</li>
<li><span class="icon elem0"></span>Events</li>
<li><span class="icon elem0"></span>e-Learning</li>
<li><span class="icon elem0"></span>Other</li>
</ul>
</li>
<li class="spiPage">
Spi
<ul>
<li><span class="icon elem1"></span>Q&A</li>
<li><span class="icon elem1"></span>Knowledge</li>
</ul>
</li>
<li class="aboutPage">
About Us
</li>
<li class="contactPage">
Contact Us
</li>
</ul>
</nav>
How can I modify the below script so if any of the resources page is in the Url, the LI with the class resourcesPage will have the active class. Only one of the parent LI will have the active class.
$(function() {
var pathName = getPageName(window.location.pathname);
if (pathName.split("_").toLowerCase() == 1) { //if the path is anything related to the home page
$("."+pathName+"Page").addClass("active"); //add the 'active' class to the homePage LI and remove it from the rest
}
else if (pathName.split("_").toLowerCase() == 1) { //if the path is anything related to the resources page
$("."+pathName+"Page").addClass("active"); //add the 'active' class to the resourcePage LI and remove it from the rest
}
else if (pathName.split("_").toLowerCase() == 1) { //if the path is anything related to the spi page
$("."+pathName+"Page").addClass("active"); //add the 'active' class to the spiPage LI and remove it from the rest
}
else if (pathName.split("_").toLowerCase() == 1) { //if the path is anything related to the about page
$("."+pathName+"Page").addClass("active"); //add the 'active' class to the aboutPage LI and remove it from the rest
}
else if (pathName.split("_").toLowerCase() == 1) { //if the path is anything related to the contact page
$("."+pathName+"Page").addClass("active"); //add the 'active' class to the contactPage LI and remove it from the rest
}
});
UPDATE:
<nav id="navMenu" class="navMenu">
<ul>
<li class="active homePage" id="home">
Home
</li>
<li class="resourcesPage" id="resources">
Resources
<ul>
<li id="resources_ins"><span class="icon elem0"></span>Institutions</li>
<li id="resources_restaurants"><span class="icon elem0"></span>Restaurants</li>
<li id="resources_businesses"><span class="icon elem0"></span>Businesses</li>
<li id="resources_events"><span class="icon elem0"></span>Events</li>
<li id="resources_elearn"><span class="icon elem0"></span>e-Learning</li>
<li id="resources_other"><span class="icon elem0"></span>Other</li>
</ul>
</li>
<li class="spiPage" id="spi">
Spi
<ul>
<li id="spi_qa"><span class="icon elem1"></span>Q&A</li>
<li id="spi_knowledge"><span class="icon elem1"></span>Knowledge</li>
<li id="spi_marriage"><span class="icon elem1"></span>Family</li>
<li id="spi_dwif"><span class="icon elem1"></span>Inter</li>
</ul>
</li>
<li class="expressionPage" id="expression">
Expression
<ul>
<li id="expression_multimedia"><span class="icon elem3"></span>Multimedia</li>
<li id="expression_eduact"><span class="icon elem3"></span>Education/Activity</li>
<li id="expression_ouwo"><span class="icon elem3"></span>Our World</li>
<li id="expression_poems"><span class="icon elem3"></span>Poems</li>
<li id="expression_other"><span class="icon elem3"></span>Other</li>
</ul>
</li>
<li class="aboutPage" id="about">
About Us
</li>
<li class="contactPage" id="contact">
Contact Us
</li>
</ul>
</nav>
So for example, in the code above, if I am on the homepage, the home LI ID will be set to active (as shown above). If I am on the resources or any of the sub resources page, the resources LI ID will be set to active class and all the other LI will remove the active class.
A script that would do what you are looking for is essentially
$(function() {
var pathName = window.location.pathname.split('/')[1];
$('li[href='+pathName+']').addClass('active').parents('li').addClass('active');
});
This is generally considered bad design and non-performant but it will do exactly what I think you are trying to do.
The reason it will be non-performant is because you aren't using efficient selectors (you don't have id attributes directly derived from the page name for example so you can't map 1:1). These kind of jquery selectors traverse the entire DOM looking for matches, and as such can't get exactly what you want. In contrast, if you have an id which is just a parsed version of the page name, then you don't have to traverse the entire DOM, and you can use $('#'+idName) which will be very fast.
More information about jquery performance: http://24ways.org/2011/your-jquery-now-with-less-suck
EDIT: Added more about actually refactoring the original document:
Rewriting the original document with ids which are the pathnames without the .php gets you:
<nav id="navMenu" class="navMenu">
<ul>
<li class="active homePage" id="index">
Home
</li>
<li class="resourcesPage" id="resources">
Resources
<ul>
<li id="resources_restaurants"><span class="icon elem0"></span>Restaurants</li>
<li id="resources_businesses"><span class="icon elem0"></span>Businesses</li>
<li id="resouces_events"><span class="icon elem0"></span>Events</li>
<li id="resouces_elearning"><span class="icon elem0"></span>e-Learning</li>
<li id="resouces_other><span class="icon elem0"></span>Other</li>
</ul>
</li>
<li class="spiPage">
Spi
<ul>
<li id="spi_qa"><span class="icon elem1"></span>Q&A</li>
<li id="spi_knowledge"><span class="icon elem1"></span>Knowledge</li>
</ul>
</li>
<li class="aboutPage">
About Us
</li>
<li class="contactPage">
Contact Us
</li>
</ul>
</nav>
With that you could rewrite your javascript to be:
$(function() {
//This double split is an easy way to parse out just the filename portion
//it equivalently means "id" in this case
var pathName = window.location.pathname.split('/')[1].split('.')[0];
//find limits results to only li tags, it is a safety method which can be
//ignored if you're confident in your html structure
$('#'+pathName).find('li').addClass('active').parents('li').addClass('active');
});
you can also use PHP to do so in case the user has JS disabled:
<?php if(expression) $style = "active"; else $style="";
<div class="something <?php echo $style ?>" >
</div>
some people disable JS, some browsers don't have good JS functions, it is a good practice to make important stuff be server side.
This is what solved the issue for me:
<nav id="navMenu" class="navMenu">
<ul>
<li class="active homePage" id="home">
Home
</li>
<li class="resourcesPage" id="resources">
Resources
<ul>
<li id="resources_ins"><span class="icon elem0"></span>Institutions</li>
<li id="resources_restaurants"><span class="icon elem0"></span>Restaurants</li>
<li id="resources_businesses"><span class="icon elem0"></span>Businesses</li>
<li id="resources_events"><span class="icon elem0"></span>Events</li>
<li id="resources_elearn"><span class="icon elem0"></span>e-Learning</li>
<li id="resources_other"><span class="icon elem0"></span>Other</li>
</ul>
</li>
<li class="spiPage" id="spi">
Spi
<ul>
<li id="spi_qa"><span class="icon elem1"></span>Q&A</li>
<li id="spi_knowledge"><span class="icon elem1"></span>Knowledge</li>
<li id="spi_marriage"><span class="icon elem1"></span>Family</li>
<li id="spi_dwif"><span class="icon elem1"></span>Inter</li>
</ul>
</li>
<li class="expressionPage" id="expression">
Expression
<ul>
<li id="expression_multimedia"><span class="icon elem3"></span>Multimedia</li>
<li id="expression_eduact"><span class="icon elem3"></span>Education/Activity</li>
<li id="expression_ouwo"><span class="icon elem3"></span>Our World</li>
<li id="expression_poems"><span class="icon elem3"></span>Poems</li>
<li id="expression_other"><span class="icon elem3"></span>Other</li>
</ul>
</li>
<li class="aboutPage" id="about">
About Us
</li>
<li class="contactPage" id="contact">
Contact Us
</li>
</ul>
</nav>
Script:
var pathName = getPageName(window.location.pathname);
var getSubPath = pathName.split("_")[0];
$('.ulHeaderMenu li').removeClass('active');
$('.ulHeaderMenu li.'+getSubPath+'Page').addClass('active');
Thanks to #lassombra for the pointer to have it working.