How to match URL with href in jQuery? - javascript

Using a list for navigation, I am looking for a clean way to apply the 'selected' class to a list item if the page URL (minus anything after the path) matches the href of the list item (minus anything after the path).
Example:
<li>dresses</li>
Apply class "selected" to the list item when the page URL includes the /p/clothing/dresses/N-10635 part of the href.
So far, I achieved partial results using:
$('.leftNav li a').each(function(){
if(window.location.href == this.href){
$(this).parents('li').addClass('selected');
}
});
<ul class="leftNav">
<li>dresses</li>
<li>capris</li>
</ul>
This, however, only applied the 'selected' class when the URL matched the href exactly - meaning it had to include the link-tracking variable as in the href (ie: ?ab=leftNav:dresses). Thinking of ways to match the "base" URL's and href's, I tried adding a data attribute to the list items to match the path only:
$('.leftNav li').each(function(){
if(window.location.href == (this).data('left-nav-href')){
$(this).addClass('selected');
}
});
<ul class="leftNav">
<li data-left-nav-href="/p/clothing/dresses/N-10635">dresses</li>
<li data-left-nav-href="/p/clothing/bottoms/capris/N-10764">capris</li>
</ul>
I attempted this with variations of window.location including: window.location.href, window.location.href.pathname, window.location.href.indexOf, window.location.href.startsWith. With this not working, I searched for a way to match the path of the URL and href regardless of additional parameters or variables, but all I can find are ways to match URL's and href's specifically with strings or parameters. All instances I could find of matching only part of a URL or href use "split" RegEx which introduces another level of complexity that I don't think my use requires. Am I missing a simpler solution?

you can use indexOf()
$(document).ready(function () {
$('.leftNav li a').each(function(){
var ThisHref = ($(this).attr('href').split('?'))[0];
if(window.location.href.indexOf(ThisHref) > -1) {
$(this).closest('li').addClass('selected');
}
});
});
Example
var url = "http://www.website.com/index/p/clothing/bottoms/capris/N-10764?ab=leftNav:capris";
$(document).ready(function () {
$('.leftNav li a').each(function(){
var ThisHref = ($(this).attr('href').split('?'))[0];
//alert(ThisHref);
if(url.indexOf(ThisHref) > -1) {
$(this).closest('li').addClass('selected');
}
});
});
.selected{
background : red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="leftNav">
<li>dresses</li>
<li>capris</li>
</ul>
Explanation:
$(document).ready(function () { // run the code after document is ready
$('.leftNav li a').each(function(){ // loop through <a> on <li>
// $(this).attr('href') will return href as string .. in your case will return something like '/p/clothing/dresses/N-10635?ab=leftNav:dresses'
// using .split('?') to separating this href string by '?'
// [0] get the first string after split (in this case it will be '/p/clothing/dresses/N-10635')
// combine all of those steps on just one line
var ThisHref = ($(this).attr('href').split('?'))[0];
// get the 'window.location.href' which is return your url ..something like 'http://www.website.com/index/p/clothing/bottoms/capris/N-10764?ab=leftNav:capris'
// try to find (first string after split) into (url/window.location.href)
if(window.location.href.indexOf(ThisHref) > -1) { // if the url contains the first string after split addClass
$(this).closest('li').addClass('selected');
}
});
});
you can read about .split() here
Note: in Vinas answer he use this.href which will return href as
string .. in your case will return something like
'/p/clothing/dresses/N-10635?ab=leftNav:dresses' and he use
location.pathname
and the code of indexOf() he try to find the location.pathname
into the href
Additional: in your case both my answer and Vinas answer will work . that's not depending on code its depending on your case and what you're trying to do .. something like .hide(0) , .slideUp(0) , fadeOut(0) all of those hide the element with same effect .. So the code always determine by the case you working with .. May be my code or even Vinas's code won't work on another case

I guess if you keep your html like
<li>dresses</li>
but change the comparisson to:
$('.leftNav li a').each(function(){
if (this.href.indexOf(location.pathname) > -1) {
$(this).parents('li').addClass('selected');
}
});
you'll get what you need!
The "if" above will check if the given path is contained in item's href property.
So, if your URL is "http://www.yourhost.com/p/clothing/dresses/N-10635?param=value", it's path (/p/clothing/dresses/N-10635) should be found, and the output for the given example would be:
<li class="selected">dresses</li>
I hope this helped! =)

Assuming there isn't any '?' character in the actual path you could use something like this for both the location and the href:
function getBaseURL(url) {
return url.split('?')[0];
}

Related

How to check if url contains parent page url?

I want to check if the current url contains the parent url to add an "active" class to the parent list item link.
jQuery(function($) {
var path = window.location.pathname;
$('ul a').each(function() {
if (this.pathname.indexOf( path )) {
$(this).addClass('active');
}
});
});
My html looks like this:
<ul>
<li><a class="list-link">Posts</a></li>
<li><a class="list-link">Blog</a></li>
<li><a class="list-link">Contact</a></li>
</ul>
When going to domain.com/contact/email I want to keep the list item to keep the "active" class.
If I understand your question correctly, you're wanting to add the active class to anchor elements in your ul list, if the anchor's text exists in the current browser path.
That can be achieved via the following (see documentation in snippet for details):
jQuery(function($) {
//var path = window.location.pathname;
var path = 'domain.com/contact/email';
// Convert path to lower case for easier matching
path = path.toLowerCase();
$('ul a').each(function() {
// Extract link label via text() method. Convert
// label to lower case for easier matching
var label = $(this).text().toLowerCase();
// Use indexOf() to check for label existing in
// path
if( path.indexOf(label) !== -1 ) {
// Add active class if match found
$(this).addClass('active');
}
});
});
.active {
background:red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<ul>
<li><a class="list-link">Posts</a></li>
<li><a class="list-link">Blog</a></li>
<li><a class="list-link">Contact</a></li>
</ul>
UPDATE
I found what I was looking for using this jQuery code:
jQuery(function($) {
var path = window.location.pathname.split( '/' )[2];
$('ul a').each(function() {
if (this.href.indexOf( path ) != -1) {
$(this).addClass('active');
}
});
});
Anchors don't have a pathname property. Change the line to check the text contained within the anchor:
if (this.textContent.indexOf( path )) {

How to call JavaScript methods on jQuery objects

Let's go straight to the point.
The following code must run on IE8, unfortunately.
It is supposed to find match the URL of the current page with the href attribute of the <a> tags present in the nav. Then swap the class of that tag from not-selected to selected or defaults to do it to the first <a> tag.
HTML
<ul id="nav">
<li><a class="not-selected" href="index.php"><span>Index Page</span></a></li>
<li>
<a class="not-selected" href="page1.php"><span>Page 1</span></a>
</li>
<li>
<a class="not-selected" href="page2.php"><span>Page 2</span></a>
</li>
</ul>
JavaScript (jQuery)
var url = $(document).attr('URL');
var isIndexPage = true;
var menu = $('#nav').children('li');
var anchors = menu.find('a');
anchors.each(function(index) {
// Is the href the same as the page?
if ($(this).href != null && anchor.href == url)
{
$(this).first().addClass('selected');
if ($(this).className.match(/\bnot\-selected\b/))
$(this).first().removeClass('not-selected');
indexPage = false;
}
else
{
// remove class="selected" if it has that class
if ($(this).className.match(/\bselected\b/))
{
$(this).first().removeClass('selected');
}
// Add class="trigger"
$(this).first().addClass('not-selected');
}
});
if (isIndexPage)
{
menu[0].childNodes[0].setAttribute('class', 'selected');
}
On the script, I get an error on the line that calls the match() function on the className attribute (which should be a string).
Why is that?
How can I fix it with jQuery or JavaScript that works on IE8?
Thank you in advance.
There is no className property of the jQuery object, you would use the hasClass method to check if the element has a class:
if ($(this).hasClass('not-selected'))
However, you don't need that check at all. You can just remove the class, and if it's not there in the first place the call will just do nothing. You can just do it like this:
$(this).addClass('selected').removeClass('not-selected');
Similarly in the else block, you don't need to check, just remove and add:
$(this).removeClass('selected').addClass('not-selected');
Actually, you don't even need the if, you can do it using toggleClass and a boolean value. This would be your entire loop:
anchors.each(function() {
var sel = $(this).href != null && $(this).href == url;
$(this).toggleClass('selected', sel).toggleClass('not-selected', !sel);
});
Also, you are using the undefined variable anchor where you should use $(this). Change this line:
if ($(this).href != null && anchor.href == url)
to:
if ($(this).href != null && $(this).href == url)
className is a native property of HTML elements, whereas you're trying to call it as a property on a jQuery object. Do either:
$(this)[0].className
or
$(this).attr('class')
Sidenote: you're are not first checking whether the element has a class or not - you're assuming it has. The second (jQuery) approach will error if the element has no class attribute, as it returns null if none is found (as opposed to the native className property which, in the absence of a corresponding class attribute, defaults to an empty string.)
you can replace the lines
if ($(this).className.match(/\bselected\b/))
with this
if ($(this).hasClass('selected'));
It's much simpler. The same for class 'not-selected'.
I think you should use plain JS for the URL and jQuery for the rest example:
JavaScript
var path = window.location.pathname;
$.each($('#nav li a'), function(index, anchor) {
if(path.indexOf($(anchor).attr('href')) != -1) {
$('#nav li a').removeClass('selected');
$(anchor).addClass('selected').removeClass('not-selected');
}
});
Here is an example: http://jsfiddle.net/2rSqL/

javascript hash tag linking

I'm trying to modify this porfolio script here: http://themes.iki-bir.com/webpaint/multipage/full/portfolio.html
It uses urls like #entry-12 (using the index number of the element to deeplink the item) and I'd like to change it to #this-is-an-item
updateURLParameter(thumb.attr("data-event-id"));
//updateURLParameter("entry-"+thumb.index());
It sets the name here (which works fine)... now it's whatever.html#this-is-an-item
But now I need to change the behaviour when they link in from the URL (as it no longer works since it's still looking for the index number instead of a name).
var deeplink = getUrlVars("#");
// DEEPLINK START IF NECESSARY
if (deeplink[0].split('entry-').length>1) {
var thmb = parseInt(deeplink[0].split('entry-')[1],0)+1;
$container.find('.item:nth-child('+thmb+')').click();
$container.find('.item:nth-child('+thmb+')').addClass("active").children('a').children('div').fadeIn(300);;
}
I'm just not sure how to do the last part, so it looks for the data-event-id instead of the index?
<li class="item installation 2013-10-13" data-event-id="installation-opening-whispering-in-the-leaves"... </li>
Try this:
var deeplink = getUrlVars("#");
var $elem;
// v--- this can be changed to .find('.item) if needed.
$container.children('.item').each(function() {
// you can use .data(...) instead of .attr("data-...")
if ($(this).data("event-id") == deeplink[0])
$elem = $(this);
});
if ($elem) {
$elem.click()
.addClass("active")
.children('a')
.children('div')
.fadeIn(300);
}
Simply iterate over all the elements in $container with the class .item, and check if the data-event-id matches the one in the URL hash. If it does, store it, and do your operations afterwards.

Remember li active state when loading to different pages?

I have my code below:
<ul id="profileList" class="nav nav-list">
<li>修改个人签名档</li>
<li>修改个人居住地</li>
<li>修改个人学校专业</li>
</ul>
Also here's the JS code:
<script type="text/javascript">
$(document).ready(function() {
// store url for current page as global variable
current_page = document.location.href
// apply selected states depending on current page
if (current_page.index(/signature/)) {
$("ul#profileList li:eq(0)").addClass('active');
} else if (current_page.match(/location/)) {
$("ul#profileList li:eq(1)").addClass('active');
} else if (current_page.match(/education/)) {
$("ul#profileList li:eq(2)").addClass('active');
} else { // don't mark any nav links as selected
$("ul#profileList li").removeClass('active');
};
});
</script>
When I click the second and third li item, they work well. But when I click the first item,
the item is not becoming active. What's the wrong and why?
In
if (current_page.index(/signature/)) {
Change to
if (current_page.match(/signature/)) {
As far as I know, String.prototype.index doesn't exist. Perhaps you wanted to use the indexOf method.
if (current_page.indexOf('signature') !== -1) {}
Also, do not use the String.prototype.match function when you just want to know if there's a match or not, use the RegExp.prototype.test function.
if (/education/.test('education')) { /*matches*/ }
However in your case, you could use the match method and instead of discarding the match, use it at your advantage:
var sections = ['signature', 'location', 'education'],
match = document.location.href.match(new RegExp(sections.join('|'), 'i')),
selectorSuffix = match? ':eq(' + sections.indexOf(match[0].toLowerCase()) + ')' : '';
$('ul#profileList li' + selectorSuffix)[(match? 'add' : 'remove') + 'Class']('active');

How can i change the css class based on keywords in url with jquery

I have the navigation bar as below
<ul>
<li class="selected"><a href=">My Profile</a></li>
<li>xxxx</li>
<li>mybook</li>
<li>Photos <span>4</span></li>
<li>Profile List</li>
</ul>
I want that if the url is www.abc.com/user/profile then profile tab class should have class selected attached
If photos then photo tab.
If we can have partial match that will be good but i am not sure if thats possible
like in url i have /user/book and myBook gets selected
Some elegant variant:
<ul class="menu">
<li><a class="profile" href="/user/profile">My Profile</a></li>
<li><a class="book" href="/user/book">My Book</a></li>
</ul>
$(document).ready(function () {
var page = document.location.href.split('/').slice(-1)[0];
$('.menu .' + page).addClass('selected');
});
You can grab the part you want with regex:
var userPage = /user\/(.+)/.exec(location.href)[1];
That will give you the part after user/. Then you could use a switch statement:
switch (userPage) {
case 'profile':
...
break;
case 'book':
...
break;
}
You would want to switch off of location.pathname. Granted that you give that <ul> a class of nav:
$(function () {
if (location.pathname.search("/user/profile") != -1) {
// page is /user/profile
$("#nav li").eq(0).addClass("selected");
} else if (location.pathname.search("/user/photos") != -1) {
// page is some/thing
$("#nav li").eq(3).addClass("selected");
}
... etc
});
Things to notice
We use $(function () {...}); as opposed to $(document).ready(function() {...});. It is less typing and more efficient
We use String.search(), which returns the index at which the string "/user/profile" appears. If the string is not found, String.search() will return -1, so if it != -1, it exists.
We also use jQuery.eq( index ) this treats elements selected by a jQuery selector as an array and returns the element of the specified index.
References
Check out jQuery's .eq here, and JavaScript's String.search here

Categories