JQuery/JavaScript: how to retain active nav state after link? - javascript

I've found many posts on how to add the active class to a nav link via jquery, but nothing on how to maintain the active state after the nav link is clicked.
Using code found on this site, I'm removing and adding the active class onclick. In an attempt to keep this active state after navigating/reloading, my thought is to set session variables via onclick, and re-add the active class.
What I have is not working.
This seems to work, but doesn't seem to be best-practice, by today's standards.
HMTL:
<nav>
<a href="about.xhtml" id="about" >About</a>
<span class="nav_divide"></span>
<a href="work.xhtml" id="work" >Work</a>
<span class="nav_divide"></span>
<a href="mission.xhtml" id="mission" >Mission</a>
<span class="nav_divide"></span>
<a href="contact.xhtml" id="contact" >Contact</a>
</nav>
CSS:
nav a.active {
border-bottom: 3px solid #d10f0f;
}
Script:
//Check for session variables.
$(document).ready(function() {
//If 'page' session is defined
if (window.sessionStorage.pageSession) {
// make selected nav option active.
var activeTab = '#' + window.sessionStorage.pageSession;
$(activeTab).addClass('active');
} else {
// If pageSession is not defined, you're at home
window.sessionStorage.pageSession = ('page', 'home');
}
//Set link location for page refresh/reload
});
// Place or remove nav active state.
$(document).on('click','nav a',function(){
//Set 'page' and 'link' variables based on nav values.
var page = this.id;
var link = this.href;
// Set 'page' and 'link' session variables based on nav values.
var window.sessionStorage.pageSession = ('page', page);
var window.sessionStorage.linkSession = ('link', link);
// Update classes.
$('nav .active').removeClass('active');
$(this).addClass('active');
// Link to nav ahref.
window.location = sessionStorage.linkSession;
});

You can use localStorage! this is an example:
//Check for session variables.
$(document).ready(function() {
// Set paramenters obj for initialization
let paramObj = {page:'current-page-name',link:location.href};
// Initialize pageSession obj to storage the current page
localStorage.setItem('pageSession', JSON.stringify(paramObj));
// Retrieve page session settings updated
let pageStorage = localStorage.getItem('pageSession') != undefined ? JSON.parse(localStorage.getItem('pageSession')) : paramObj;
// make selected nav option active.
let activeTab = '#' + pageStorage.page;
$(activeTab).addClass('active');
//Set link location for page refresh/reload
$(document).on('click','nav a',function(e){
e.preventDefault();
//Set 'page' and 'link' variables based on nav values.
let page = JSON.parse(localStorage.getItem('pageSession')).page;
let link = JSON.parse(localStorage.getItem('pageSession')).link;
// Set 'page' and 'link' session variables based on nav values.
localStorage.setItem('pageSession', JSON.stringify({page:$(this).attr('id'), link:$(this).attr('href')}));
// Update classes.
$('nav .active').removeClass('active');
$(this).addClass('active');
// Link to nav ahref.
window.location = $(this).attr('href');
});
});
nav a.active {
border-bottom: 3px solid #d10f0f;
}
<nav>
<a href="javascript:;" id="home" >Home</a>
<span class="nav_divide"></span>
<a href="javascript:;" id="about" >About</a>
<span class="nav_divide"></span>
<a href="javascript:;" id="work" >Work</a>
<span class="nav_divide"></span>
<a href="javascript:;" id="mission" >Mission</a>
<span class="nav_divide"></span>
<a href="javascript:;" id="contact" >Contact</a>
</nav>
There are a lot of ways for doing that. This is only one of ways!
--------------- EDITED ---------------
Now the code initialize pageSession on every page, so the JSON.parse(...) was solved!
Try it here jsfiddle. Now it works!
I hope it help.

Related

How can I keep class active after refreshing the page (using jQuery)

I have been searching for whole day and found several examples but none of them work correctly. I have a navigation bar and I want to keep class active after clicking on it and refreshing page but it gets lost.
This is my code:
HTML
<li class="sub-menu" style="border-bottom: 1px solid grey;">
<a class="menuItem active" href="#Url.Action("Index", "Administrator")">
<i class="fa fa-th"></i>
<span>Index</span>
</a>
</li>
<li class="sub-menu">
<a class="menuItem normal" href="#Url.Action("Products", "Administrator")">
<i class="fa fa-shopping-cart"></i>
<span>product</span>
</a>
</li>
Javascript
var retrievedObject = localStorage.getItem('classChange');
if (retrievedObject) {
$('.menuItem').addClass(retrievedObject)
}
$(".menuItem").click(function () {
if ($(this).hasClass("normal")) {
$(this).removeClass('normal').addClass('active');
localStorage.setItem('classChange', 'active');
} else {
$(this).removeClass('active').addClass('normal');
localStorage.setItem('classChange', 'normal');
}
});
I expected to change class on active after click but all classes change after click, I understand why it happens but don't know how to fix it.
Can you give each element an id value and, in the function, store in the local storage the id of the element and the class? Then, on reload check for the both id's?
And if you need for more elements you can save an array of the id's and then use it to loop between all id's if necessary.
So something like this:
var ids = ['id1','id2'];
for(i of ids) {
var retrievedObject = localStorage.getItem(i);
if (retrievedObject) {
var id = "#" + i;
$(id).addClass(retrievedObject);
}
}
$(".menuItem").click(function (event) {
if ($(this).hasClass("normal")) {
$(this).removeClass('normal').addClass('active');
localStorage.setItem('classChange', 'active');
} else {
$(this).removeClass('active').addClass('normal');
localStorage.setItem(event.target.id, 'normal');
}
});
The code
if (retrievedObject) {
$('.menuItem').addClass(retrievedObject)
}
should be wrapped on jQuery.ready().

Show last active div on refresh JS

I have a fairly basic navigation tab on a single-page website that shows/hides divs. However, when I refresh the page, it goes back to the landing "page" div instead of staying on the current tab. I am using the following JS to switch between tabs and I would like to keep using this method if possible:
var links = document.getElementById('navs').getElementsByTagName('a');
for(var i = 0, link; link = links[i]; i++) {
link.onclick = showContent;
// Hide content divs by default
var contentdiv = getContentDiv(link)
if (contentdiv == null){
continue;
}
contentdiv.style.display = 'none';
}
// Show the first content div
if(links.length > 0) showContent.apply(links[0]);
var current;
function showContent() {
// hide old content
if(current) current.style.display = 'none';
current = getContentDiv(this);
if(!current) return true;
current.style.display = 'inline-block';
return true;
}
function getContentDiv(link) {
var linkTo = link.getAttribute('href');
console.log(linkTo);
// Make sure the link is meant to go to a div
if(linkTo.substring(0, 2) != '#!') return;
linkTo = linkTo.substring(2);
return document.getElementById(linkTo);
}
I know it refreshes to the landing div because of
if(links.length > 0) showContent.apply(links[0]);
However, I was hoping to use this method and store the link iteration number in a variable called current_link and then be able to call if(links.length > 0) showContent.apply(links[current_link]); or even if(links.length > 0) showContent.apply(current_link);
I have tried a couple ways, but it ends up just saving either the first or last tab in the navigation bar. Also the page refreshes to the default div, but the url stays the same. EX. The URL is http://example.com/#!tab1 even though the page is displaying http://example.com/#!home
This is the html:
<nav class="navbar navbar-fixed-top" id= "navs" role="navigation">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<div class="navbar-brand">
<a id="logo" href="#!home"><img id="logo-pic" src="images/name.png" alt="" width="50%" height="auto"></a>
</div>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="navbar" id="navbar-collapse-1">
<ul class="nav navbar-right navbar-nav">
<li class="dropdown">
tab1
</li>
<li>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">tab2</a>
<ul class="dropdown-menu dropdown-menu-right pull-center">
<li>tab21</li>
<li>tab22</li>
</ul>
</li>
<li>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">tab3</a>
<ul class="dropdown-menu dropdown-menu-right pull-center">
<li>resume</li>
<li>tab31</li>
<li>tab32</li>
</ul>
</li>
<li>
tab4
</li>
<li>
tab5
</li>
</ul>
</div>
</div>
<!-- /.container -->
</nav>
The best way to persist page state is to leverage the url history.
E.g. when the user clicks on a tab, instead of just doing the navigation:
Create a hashchange event handler
window.onhashchange = () => { ... };
or:
window.addEventListener('hashchange', () => ...);
So you might do something like:
const navigate = () => open_tab(location.hash.substr(1)); // get rid of the '#'
window.addEventListener('hashchange', navigate);
You also want to navigate when the page loads:
navigate();
Now, when the user clicks a tab, or whatever, change the hash of the page location:
location.hash = "tab1";
This is a little extra work but the benefits are huge:
Refreshing the page works as expected
If the user bookmarks the page, they bookmark the state of the UI
Forward and backward navigation now work as expected.

GET Basename of URL then put active class to navbar

Example Link: http://localhost/test/page.php
I have a JavaScript code that will put an active class to a navbar if the url of that href ==== current_url.
Current JavaScript (Only puts active class to sidebar)
<script type="text/javascript">
jQuery(function($) {
var path = window.location.href; // because the 'href' property of the DOM element is the absolute path
$('ul a').each(function() {
if (this.href === path) {
$(this).addClass('sub-menu active');
$(this).parent().closest("li").addClass('active');
$(this).parent().parent().closest("li").addClass('active');
}
});
});
</script>
I want to make it work also if the link has a page.php?success. There will also be an active class as long as the page.php is there regardless of what is after the ?.
I've tried the following script below to extract the basename but now it doesn't work at all, pages with or without ?.
Tried script (Supposed to put active class to sidebar even if the url has page.php?success in it.
<script type="text/javascript">
jQuery(function($) {
var patharray = window.location.pathname.split( '/' );
var reallink = patharray[2];
$('ul a').each(function() {
if (this.href === reallink) {
$(this).addClass('sub-menu active');
$(this).parent().closest("li").addClass('active');
$(this).parent().parent().closest("li").addClass('active');
}
});
});
</script>
With the example link above. The script returns page.php And the href's inside the navbar are just page1.php, page2.php etc... So I know it should work since the retrieved reallink is equal to the href of the navbar.
My sidebar
<li class="sub-menu"> // Sidebar with no submenu
<a class="" href="page1.php">
<i class="icon-calendar"></i>
<span>This is page 1</span>
</a>
</li>
<li class="sub-menu"> // Sidebar with a submenu
<a href="javascript:;" class="">
<i class="icon-group"></i>
<span>This has sub pages</span>
<span class="arrow"></span>
</a>
<ul class="sub">
<li><a class="" href="page2.php">This is page 2</a></li>
<li><a class="" href="page3.php">This is page 3</a></li>
</ul>
</li>
So the first JavaScript puts an active class both to the parent and the child if the href = url is met. But with the 2nd script nothing works.
I guess changing this line in the First script will make it work
var path = window.location.href.split( '?' )[0];

Change and keep active class in navigation menu, on click and refresh

I am trying to create a navigation menu using css and js. I have styled the necessary classes, and nav works with js animation, however I am having a problem changing the class of li to active onclick by the user, and saving this in local storage so that it remains when the page refreshes.
This is the code that I have now:
http://codepen.io/anon/pen/wfpti
Javascript:
var foundActive = false, activeElement, linePosition = 0, menuLine = $("#navmenu #menu-line"), lineWidth, defaultPosition, defaultWidth;
$("#navmenu > ul > li").each(function() {
if ($(this).hasClass('active')) {
activeElement = $(this);
foundActive = true;
}
});
Html:
<div id='navmenu'>
<ul>
<li class='active'><a href='link1.php'>link1</a></li>
<li><a href='link2.php'>link2</a></li>
<li><a href='link3.php'>link3</a></li>
<li><a href='link4.php'>link4</a></li>
<li><a href='link5.php'>link5</a></li>
<li><a href='link6.php'>link6</a></li>
<li><a href='link7.php'>link7</a></li>
</ul>
</div>
What I would like to achieve is that when I press, for example, "link3" is that it goes to link3.php, and the navigation menu then shows link3 as the active class link, while removing the previous active class for link1.
Just try to add class on click event this function will stop your active links. this may works for you. if you want to add active class after refreshing a page then store it to javascript cookies.
$("#navmenu > ul > li").click(function()
{
$(this).closest('ul').find('li').each(function()
{
$(this).removeClass('active');
});
$(this).addClass('active');
defaultWidth = lineWidth = activeElement.width();
defaultPosition = linePosition = activeElement.position().left;
menuLine.css("width", lineWidth);
menuLine.css("left", linePosition);
});

How to dynamically add a class to li item and change its background color using javascript and css

Here I have a list, what I want to do is I need to change the list ( li ) background color to different one after click on a specific list item. the thing is once it click on the link page will be redirected and refresh. please can me suggest a solution for to get this done?
<div id="main-menu">
<ul id="main-menu-list">
<li id="menu-home">Home</li>
<li id="menu-profile">My Profile</li>
<li id="menu-dashboard">My Dashboard</li>
<li id="menu-search">Search</li>
</ul>
</div>
what i did for this :
Java Script :
var make_button_active = function()
{
//Get item siblings
var siblings =($(this).siblings());
//Remove active class on all buttons
siblings.each(function (index)
{
$(this).removeClass('active');
}
)
//Add the clicked button class
$(this).addClass('active');
}
//Attach events to menu
$(document).ready(
function()
{
$("#main-menu li").click(make_button_active);
}
)
CSS :
#main-menu-list li.active {
background: #0040FF;
}
It's a little difficult to tell exactly what you want to do, but here's some quick and dirty (and untested) code:
/// when we click on an `a` tag inside the `#main-menu-list`...
$('#main-menu-list').on('click', 'a', function(e) {
// stop the link from firing
e.preventDefault();
e.stopPropagation();
// change the list item's background to green
$(this).closest('li').addClass('myClassName').css('background-color', 'green');
// do anything else, e.g. load in pages via ajax...
});
You could use CSS to apply the green background color, instead of jQuery:
.myClassName { background-color: green; }
This will stop the page from navigating, and I don't know if that's your intention. If you want to check the currently-loaded page against the menu to find the current item, you could do this (on page load) instead:
var currentPage = window.location.pathname;
$('#main-menu-list').find('a[href^="' + currentPage + '"]').closest('li').addClass('active');
EDIT:
Your amended Javascript code can be simplified to the following:
$('#main-menu li').on('click', 'a', function (e) {
e.preventDefault();
e.stopPropagation();
// only do the following if the clicked link isn't already active
if(!$(this).closest('li').hasClass('active')) {
$(this).closest('ul').find('.active').removeClass('active');
$(this).closest('li').addClass('active');
// load in your content via ajax, etc.
}
});
JSFiddle example
For each page you can add a class to the current list item that has "where the user is"..
CSS:
.selectedItem{
background-color: orange;//whatever color your want for the selected tab..
}
Then for each of your pages,
say you're in Dashboard.html
your menu code will look like:
<div id="main-menu">
<ul id="main-menu-list">
<li id="menu-home">Home</li>
<li id="menu-profile">My Profile</li>
<li id="menu-dashboard" class="selectedItem">My Dashboard</li>
<li id="menu-search">Search</li>
</ul>
</div>
in profile.html:
<div id="main-menu">
<ul id="main-menu-list">
<li id="menu-home">Home</li>
<li id="menu-profile" class="selectedItem">My Profile</li>
<li id="menu-dashboard">My Dashboard</li>
<li id="menu-search">Search</li>
</ul>
</div>
and so on..
You need to change the background color when the document is loaded (i.e. in document.ready).
Then you need a mechanism to connect the currently loaded page to one of your list items.
$(document).ready(function(){
//get the url from the current location or in some other way that suits your solution
//perhaps use window.location.pathname
var moduleId = "dashboard" // hardcoded to dashboard to make the point :);
$("#menu-"+moduleId).css("background-color", "#ccc");
});
http://jsfiddle.net/9JaVn/1/

Categories