Example link: http://localhost/test/page.php?success
I'm curious about this. And I'm also new to JavaScript so it's not really a surprise but I understand the code below, I just do not know why it works away with what I seem to understand. See this question for more reference.
I have this JavaScript:
<script type="text/javascript">
jQuery(function($) {
var path = window.location.href.split( '?' )[0];
$('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>
The 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>
The code puts an active class to the menu on the sidebar which href is equals to the current url. But window.location.href returns the whole url but what is inside the href's are just the page.php. So why does this.href === path work? When window.location.href.split( '?' )[0] returns http://localhost/test/page.php and the href is just page.php.
The href property of an anchor is normalized to an absolute value.
See this example:
HTML:
Test
JS:
var a = document.querySelector('a');
console.log(a.href);
In this instance the relative URL is being resolved to the location of the document containing the a element. You can use the base element to control the resolution of relative URLs.
Related
I have a side menu and I want to display the active class when it loads the page.
The obvious answer would be to do this with jquery in every page but it repeats tons of code and it's boring.
So I used this in a app.js globally:
//Active side-menu
$('.nav-item').click(function () {
$(this).addClass('active');
});
But this doesn't work because it puts active and when it loads the page this class is removed after loading the html
What can I do?
<ul class="nav">
<li class="nav-item">
<a class="nav-link" href="general-setup" onclick="gitLabFetch()" id="createEnviromentTab">
<img src="../resources/img/icons/create-icon.png" alt="" class="menuIcon">
<span class="menu-title">Create Environment</span>
</a>
</li>
//A lot of li elements
<ul>
I think that on page load, you should get the url, try to find it on the menu with javascript and then add the active class to the nav-item, something like this:
$(document).ready(function() {
var url = window.location.pathname + window.location.search;
$('ul.nav a.nav-link[href="' + url + '"]').parent().addClass('active');
});
A little example, you might need to tweak the url part:
$(document).ready(function() {
var url = 'general-setup';//window.location.pathname + window.location.search;
$('ul.nav a.nav-link[href="' + url + '"]').parent().addClass('active');
});
.active {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="nav">
<li class="nav-item">
<a class="nav-link" href="general-setup" onclick="gitLabFetch()" id="createEnviromentTab">
<img src="../resources/img/icons/create-icon.png" alt="" class="menuIcon">
<span class="menu-title">Create Environment</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="general-setup2" onclick="gitLabFetch()" id="createEnviromentTab">
<img src="../resources/img/icons/create-icon.png" alt="" class="menuIcon">
<span class="menu-title">Create Environment</span>
</a>
</li>
//A lot of li elements
<ul>
Ok, so after further thought i have come up with a solution.
An approach i would take is to add a data attribute to anchor onto, this gives you the freedom to define routes that your list items link to and style them accordingly based on route...
(() => {
$('li')
.filter((i, li) => $(li).data('route') === window.location.pathname)
.addClass('active')
})()
<li data-route="/">HOME</li>
<li data-route="/friends">Friends</li>
<li data-route="/profile">Profile</li>
<li data-route="/blog">Blog</li>
As you can see, i run over all the list-items and filter out all the items that do not have data-route attributes that match the window.location.pathname, after i am left with the filtered list, i apply an active class to the matched items.
I'm trying to create a stacked navigation list that highlights which item you have selected. It looks like this.
<div class="page-list">
<ul class="nav nav-pills nav-stacked">
<li><a href="Page1.html" > Page1 </a></li>
<li><a href="Page2.html" > Page2 </a></li>
<li><a href="Page3.html" > Page3 </a></li>
<li><a href="Page4.html" > Page4 </a></li>
<li><a href="Page5.html" > Page5 </a></li>
<li><a href="Unavailable.html" > Page6 </a></li>
<li><a href="Unavailable.html" > Page7 </a></li>
</ul>
</div>
The issue I am having is that the last two pages share the same link and I cant seem to get just the selected page to be highlighted in the list.
I was using this for my JavaScript.
<script>
$(function(){
$('a').each(function() {
if ($(this).prop('href') == window.location.href) {
$(this).addClass('current');
}
});
});
</script>
But this causes all links to the same page to highlight.
I tried solving it with this, but now no links highlight when clicked.
<script>
$(".page-list a").click(function() {
$(this).parent().previoussibling().find('a').removeClass('current');
$(this).addClass("current");
});
</script>
One way to fix this would be to create a query string to indicate which link should be highlighted.
...
<li><a href="Unavailable.html?page=6" > Page6 </a></li>
<li><a href="Unavailable.html?page=7" > Page7 </a></li>
...
Then in Javascript, read the query string and decide which page to highlight. This StackOverflow question can help you read the query string.
You could also accomplish this by using cookies if you don't want your users to see www.yourwebsite.com/Unavailable.html?page=7. See this tutorial for using cookies in JavaScript. There are a number of libraries out there that can help you when using cookies if you prefer that route.
Which ever way you choose to pass the information on to the next page, you will need to add an id to the a tags (or some other way to uniquely identify each link) so you can highlight the appropriate link.
Here is an example using the query string idea:
<div class="page-list">
<ul class="nav nav-pills nav-stacked">
...
<li><a id="6" href="Unavailable.html?page=6" > Page6 </a></li>
<li><a id="7" href="Unavailable.html?page=7" > Page7 </a></li>
</ul>
</div>
<script>
$(function(){
$('a').each(function() {
if ($(this).attr('id') == getParameterByName('page')) {
$(this).addClass('current');
}
});
});
function getParameterByName(name) {
//this code is taken directly from https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript#answer-901144
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
</script>
JSFiddle: http://jsfiddle.net/5qweu58f/4/
HTML (generated using XSLT):
<div id="dvExpProvHolder" class="hidOverflow innerDivCenter">
<ul class="uSPStyle" id="uSPStyle">
<li class="setRelative">
<a class="tfLink clickMe current" title="Care" data-toggle=".tfLink1" id="current" href="javascript:void(0);"><img src="theImages/imgMenu.png" id="imgFirstM" class="imgExpCol" />Care</a>
<ul class="uSPStyle uSPInner" style="width: 80%;">
<li><a class="tfLink clickMe" title="This is sub" data-toggle=".tf1SLink1" href="javascript:void(0);">This is sub</a></li>
</ul>
</li>
<li>
<a class="tfLink clickMe" title="Breast Cancer" data-toggle=".tfLink2" href="javascript:void(0);"><img src="theImages/imgMenu.png" id="imgFirstM" class="imgExpCol" />BC</a>
<ul class="uSPStyle uSPInner" style="width: 80%;">
<li><a class="tfLink clickMe" title="OUR LINK" data-toggle=".tf1SLink2" href="javascript:void(0);">OUR LINK</a></li>
</ul>
</li>
<li>
<a class="tfLink clickMe" title="About" data-toggle=".tfLink3" href="javascript:void(0);">About</a>
</li>
<li>
<a class="tfLink clickMe" title="Anxiety" data-toggle=".tfLink4" href="javascript:void(0);">Anxiety</a>
</li>
<li>
<a class="tfLink clickMe" title="Services" data-toggle=".tfLink5" href="javascript:void(0);">Services</a>
</li>
</ul>
</div>
Why doesn't the first UL lose the current class when another UL
is clicked? everything else works as expected.
The issue comes up when I would want the visitor to see BC > OUR LINK
section which shows "This is for second link sublink 1" without having to come to the page and then click on it. But because
they are all in one page, there is no way to do that out of the box.
I was wondering if there is a way to specify a query string in the
Url and use that to go directly to the sublink? For example:
http://www.myweb1.com/pages.aspx?id=098&menulink=2.1. The 2.1 would represent it is the second main menu and the first submenu. Is there
any way to incorporate that into my Jquery script?
Expanding on the examples from the authoritative question on the subject (How can I get query string values in JavaScript?) to solve this particular problem, you could use any of those methods for parsing window.location and taking action based on a query string parameter.
A working example is below, using a fake URL instead of window.location, as the snippet is in a sandboxed frame. This example uses URI.js, but there are many other options.
function log (o) {
var el = document.createElement('div');
el.innerHTML = o;
document.body.appendChild(el);
}
document.getElementById('button-1').onclick = function () {
log('Button 1 clicked!');
};
document.getElementById('button-2').onclick = function () {
log('Button 2 clicked!');
};
//Grab the "click" query string parameter. The button with the specified ID will be clicked.
//Using a fake URL instead of window.location inside this sandboxed frame
document.getElementById(URI('http://example.com?click=button-1').search(true)['click']).click();
<script src="https://cdnjs.cloudflare.com/ajax/libs/URI.js/1.16.1/URI.js"></script>
<button id="button-1">Button 1 - Auto-Clicked</button>
<button id="button-2">Button 2 - Not Auto-Clicked</button>
! Latest I've tried. I put it in my head.php which I just include. I'll send over my files if you'd want to see them personally.
Directory of my folder
Main_Folder
-Main_files
-- JS_Folder
---- Js Files
-- Includes_Folder
---- Head.php is here
<script type="text/javascript">
jQuery(function($) {
var path = window.location.href; // because the 'href' property of the DOM element is the absolute path
//alert($('ul a').length);
$('ul a').each(function() {
if (this.href === path) {
$(this).addClass('sub-menu active');
}
//alert(this.href);
});
});
</script>
Whole sidebar:
<div class="sidebar-scroll">
<div id="sidebar" class="nav-collapse collapse">
<!-- BEGIN SIDEBAR MENU -->
<ul class="sidebar-menu">
<li class="sub-menu">
<a class="" href="panel-admin.php">
<i class="icon-dashboard"></i>
<span>Dashboard</span>
</a>
</li>
<li class="sub-menu">
<a href="javascript:;" class="">
<i class="icon-briefcase"></i>
<span>Employees</span>
</a>
</li>
<li class="sub-menu">
<a href="javascript:;" class="">
<i class="icon-book"></i>
<span>Students</span>
</a>
</li>
<li class="sub-menu">
<a href="javascript:;" class="">
<i class="icon-calendar"></i>
<span>Scheduling</span>
<span class="arrow"></span>
</a>
<ul class="sub">
<li><a class="" href="admin-foreign.php">Foreign Languages</a></li>
<li><a class="" href="admin-esl.php">ESL Local</a></li>
<li><a class="" href="admin-workshop.php">Summer Workshops</a></li>
</ul>
</li>
<li class="sub-menu">
<a href="javascript:;" class="">
<i class="icon-pencil"></i>
<span>Enroll</span>
<span class="arrow"></span>
</a>
<ul class="sub">
<li><a class="" href="general.html">Foreign Languages</a></li>
<li><a class="" href="button.html">ESL Local</a></li>
<li><a class="" href="slider.html">Summer Workshops</a></li>
</ul>
</li>
</ul>
<!-- END SIDEBAR MENU -->
class="sub-menu" is needed to make it dropdown menus drop. So the active version is class="sub-menu active". In case of a 2 level dropdown menu, both the main bar and sub bar are to be set to active.
This is my side bar.
<div class="collapse navbar-collapse navbar-ex1-collapse">
<ul class="nav navbar-nav side-nav">
<li>
<i class="fa fa-fw fa-dashboard"></i> Overview
</li>
<li>
<i class="fa fa-fw fa-dashboard"></i> Employees
</li>
</ul>
</div>
I've tried the following below but none works on my case:
Update class attribute based on page URL
https://css-tricks.com/snippets/jquery/add-active-navigation-class-based-on-url/
First sample code
$('.menu li a').each(function(){ //check thru all <a> elements inside <li> inside .menu
var pagename= location.pathname.split('/').pop(); // get current pages filename (just filename)
if($(this).prop("href") == pagename){
$('.menu li').removeClass("active"); // remove all active class
$(this).parent("li").addClass("active"); //put active in parent of <a> which is <li>
}
});
In the first one, I've changed the menu to collapse navbar-collapse navbar-ex1-collapse and collapse only but neither works.
In the second sample code, I've tried doing the following:
$(function() {
$('nav a[href^="/' + location.pathname.split("/")[2] + '"]').addClass('active');
});
I put [2] since I'm currently in the localhost. So it would be localhost/folder_name/index.php.
I also tried putting "/index.php"/ but when I click that it directs me to localhost/index.php instead of localhost/folder_here/index.php.
Third sample code
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('active');
}
});
});
Still doesn't work. I've change $('ul a) to $('div ul a) and $('div li ul a).
EDIT: Just to be sure, the script created is just included by include('js/js_file.js');. This line should be before or after the html is loaded?
As suggested by David Thomas I've tried the following below. But it doesn't work.
var url = 'window.location.pathname';
$('.nav a').each(function() {
// get the absolute URL from the <a> element:
var href = this.href,
// get the current page and file-type:
pageAndFile = href.split('/').pop();
// if the location ends with the pageAndFile found in
// the current <a> element (using String.prototype.endsWith())
// we add the 'active' class-name:
if (url.endsWith(pageAndFile)) {
$(this).closest('li').addClass('sub-menu active');
}
});
One approach:
// obviously, use 'document.location'/'window.location' in the real thing:
var fakeLocation = 'http://www.example.com/index.php';
$('.nav a').each(function() {
// get the absolute URL from the <a> element:
var href = this.href,
// get the current page and file-type:
pageAndFile = href.split('/').pop();
// if the location ends with the pageAndFile found in
// the current <a> element (using String.prototype.endsWith())
// we add the 'active' class-name:
if (fakeLocation.endsWith(pageAndFile)) {
$(this).closest('li').addClass('active');
}
});
.active {
border: 1px solid red;
}
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="collapse navbar-collapse navbar-ex1-collapse">
<ul class="nav navbar-nav side-nav">
<li> <i class="fa fa-fw fa-dashboard"></i> Overview
</li>
<li> <i class="fa fa-fw fa-dashboard"></i> Employees
</li>
</ul>
</div>
JS Fiddle demo.
For those browsers that don't implement String.prototype.endsWith():
// simple shim for String.prototype.endsWith(), for browsers that
// don't yet implement the same:
String.prototype.endsWith = String.prototype.endsWith || function(testString) {
// creates a regular expression from the passed-in string, followed by the '$'
// character which signifies that the passed-in string must be followed by the
// end-of-string:
var reg = new RegExp(testString + '$');
// using RegExp.prototype.test() to test that the String we're testing,
// the 'this,' is matched by the created regular expression:
return reg.test(this);
};
var fakeLocation = 'http://www.example.com/index.php';
$('.nav a').each(function() {
// get the absolute URL from the <a> element:
var href = this.href,
// get the current page and file-type:
pageAndFile = href.split('/').pop();
// if the location ends with the pageAndFile found in
// the current <a> element (using String.prototype.endsWith())
// we add the 'active' class-name:
if (fakeLocation.endsWith(pageAndFile)) {
$(this).closest('li').addClass('active');
}
});
.active {
border: 1px solid red;
}
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="collapse navbar-collapse navbar-ex1-collapse">
<ul class="nav navbar-nav side-nav">
<li> <i class="fa fa-fw fa-dashboard"></i> Overview
</li>
<li> <i class="fa fa-fw fa-dashboard"></i> Employees
</li>
</ul>
</div>
JS Fiddle demo.
And, without jQuery, you could do much the same:
// simple shim for String.prototype.endsWith(), for browsers that
// don't yet implement the same:
String.prototype.endsWith = String.prototype.endsWith || function(testString) {
var reg = new RegExp(testString + '$');
return reg.test(this);
};
// again, in real-world non-demo use you should use 'document.location':
var fakeLocation = 'http://www.example.com/index.php',
// finding the last portion of the fakeLocation variable:
currentPage = fakeLocation.split('/').pop(),
// getting all the a elements with an href attribute that ends
// with the currentPage string (after escaping the special
// characters with the (ugly) regular expression) and the
// attribute-ends-with ('attribute$=value') selector:
activeAElements = document.querySelectorAll('.nav a[href$=' + currentPage.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") + ']');
// using Array.prototype.forEach to iterate over the array-like
// activeAElements NodeList:
Array.prototype.forEach.call(activeAElements, function(a) {
// the first argument of the function is the array-element,
// here an <a> element node;
// we're adding the 'active' class-name to the parentNode of any <a>
// element that was found by the above selector:
a.parentNode.classList.add('active');
});
.active {
border: 1px solid red;
}
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="collapse navbar-collapse navbar-ex1-collapse">
<ul class="nav navbar-nav side-nav">
<li> <i class="fa fa-fw fa-dashboard"></i> Overview
</li>
<li> <i class="fa fa-fw fa-dashboard"></i> Employees
</li>
</ul>
</div>
JS Fiddle demo.
As to why your own attempts failed:
$('.menu li a').each(function(){
var pagename= location.pathname.split('/').pop();
// the HTMLAnchorElement.href is the absolute URL formed
// by the href attribute; to find the actual string from
// an <a> element, you'd need to use either JavaScript:
// - this.getAttribute('href');
// or jQuery's:
// - $(this).attr('href');
if($(this).prop("href") == pagename){
$('.menu li').removeClass("active");
$(this).parent("li").addClass("active");
}
});
Your second attempt:
$(function() {
// this won't work because your JavaScript will return 'index.php',
// and pass that into the attribute selector; unfortunately this
// includes the period ('.'), which is a special character in CSS
// and has to be double escaped, first for the JavaScript and then
// the CSS
$('nav a[href^="/' + location.pathname.split("/")[2] + '"]').addClass('active');
// with that in mind, you'd need to do (something like) the following,
// which - as in my own code - replaces all special characters with
// a double-escaped version of that character (so '.' becomes '\\.'):
$('nav a[href^="/' + location.pathname.split("/")[2].replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") + '"]').addClass('active');
});
Your third attempt:
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('active');
}
});
});
Looks like it should work, albeit you're adding (or should be adding) the 'active' class-name to the <a> element, rather than the ancestor <li> element.
References:
JavaScript:
Array.prototype.forEach().
Array.prototype.pop().
document.querySelectorAll().
Element.classList API.
Element.getAttribute().
Function.prototype.call().
Guide to regular expressions in JavaScript.
Node.parentNode.
String.prototype.endsWith().
new RegExp() Regular Expression constructor.
RegExp.prototype.test().
String.prototype.split().
jQuery:
addClass().
attr().
each().
prop().
Assuming location.pathname.split("/")[2] returns the expected parameter, the problem is
$('nav a[href^="/'
should be
$('.nav a[href^="'
.nav is a class, not an element, in your example
problem in your script......
$(function() {
$('.nav a[href^="' + location.pathname.split("/")[2] + '"]').addClass('active');t
});
I have some javascript that will find the current URL and set as li to class active. What I then need it to do so that the accordion menu will function correctly is to replace the URL in the associated a href with "#".
ie.
<li><a id="Create" href="../Create/Create.html"> Create</a>
needs to be changed to:
<li><a id="Create" href="#"> Create</a>
Here is my html:
<ul class="topnav">
<li class="">
<a id="Dashboard" href="../dashboard/dashboard.html"> Dashboard</a>
</li>
<li><a id="Create" href="../Create/Create.html"> Create</a>
<ul>
<li><a id="Monster" href="../Monster/Monster.html"> Monster</a>
<ul>
<li><a id="Custom" href="../Custom/Custom.html"> Custom</a>
<ul>
<li><a id="New" href="../New/New.html"> New</a></li>
<li><a id="Drafts" href="../Drafts/Drafts.html">> Drafts</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
And current Javascript that will give the current page a class of "active" on the corresponding "li" tag.
var url = window.location;
$('ul.topnav a').filter(function() {
return this.href == url;
}).parent().addClass('active');
This would be easily achieved utilizing the ID:
document.getElementById("Create").href="#";
but this is not an option due to the magnitude of the site. It needs to be done via javascript.
I've tried to do this with
document.getElementByClassName('li.active a').href="#";
but that is not working. I'm also concerned this might strip out all hrefs under that li.
Any help would be greatly appreciate!