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/
Related
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];
}
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.
I need help figuring the last bit of this out. I am trying to change a set of anchor elements in the form of <a href='#some link'> to be this form: <a href='some_link.html'>. I'm sure it's something small I'm overlooking...below is a link as an example. Thanks!
http://jsfiddle.net/TGxANAHEiiMx/Dh8JM/24/
You're iterating all <a> elements, also the ones without an href attribute (i.e. the ones that have a name attribute instead). Use a[href] instead, which only selects <a> elements which actually have an href attribute to replace: http://jsfiddle.net/Dh8JM/25/.
$('a[href]').attr(...);
I'd suggest:
$('a').each(
function(){
var h = this.href.substring(this.href.indexOf('#')+1);
if (h == 'top_page'){
return false;
}
else {
this.href = h.replace(/ /g, '_') + '.html';
}
});
JS Fiddle demo.
The above will turn a elements from:
<a href='#Tax Services'>Tax Services</a>
Into:
Tax Services
Would this help
$("a[href='#top_page']").attr("href","some_link.html");
You're encountering an error where some of your <a> tags don't have an href attribute defined. Here is a working fiddle.
$('a').attr('href', function(i, val) {
// skip the undefined ones with val !== undefined
if (val !== '#top_page' && val !== undefined) {
return val.replace(/\#/, '').replace(/\s/g, '_') + '.html';
}
});
finally i did this by following javascript..
function extractPageName(hrefString)
{
var arr = hrefString.split('/');
return (arr.length<2) ? hrefString : arr[arr.length-2].toLowerCase() + arr[arr.length-1].toLowerCase();
}
function setActiveMenu(arr, crtPage)
{
for (var i=0; i<arr.length; i++)
{
if(extractPageName(arr[i].href) == crtPage)
{
if (arr[i].parentNode.tagName != "DIV")
{
arr[i].className = "selected";
arr[i].parentNode.className = "selected";
}
}
}
}
function setPage()
{
hrefString = document.location.href ? document.location.href : document.location;
if (document.getElementById("but_a")!=null)
setActiveMenu(document.getElementById("but_a").getElementsByTagName("a"), extractPageName(hrefString));
}
if i click the ul without clicking the link.. its working.. when i click the link. it works until the page loads. after the page load, the ul back groud going default class not "selected" class..am new to tis.. am struggling so hard.. need help..??
I've added a jdFiddle with an example here:
http://jsfiddle.net/Suren/u4szQ/1/
$(document).ready(function() {
$("a.button").click(function () {
$(this).toggleClass("selected");
});
});
You've got too much javascript there.
After your posted fiddle. Here is a working fiddle.
Note you have a great deal of malformed HTML. You can't place divs in between list items. You can't have multiple objects on a page with the same ID (use a class instead).
After clicking on anchor the page is going to navigate to the url set on anchor's href attribute so whatever javascript operation you do is going to be lost after the page is loaded.
If you want to highlight the selected link the you can probably send the link id or some identifier along with the url and then check for it on page load and set the appropriate link selected.
By the way toggleClass adds or removes one or more classes from each element in the set of matched elements, depending on either the class's presence or the value of the switch argument.
I have this snippet of code to parse the URL and add a class to the <body>tag of my HTML page.
var pathname = window.location.pathname;
var pathSlashesReplaced = pathname.replace(/\//g, " ");
var pathSlashesReplacedNoFirstDash = pathSlashesReplaced.replace(" ","");
var newClass = pathSlashesReplacedNoFirstDash.replace(/(\.[\s\S]+)/ig, "");
$("body").attr("class",newClass);
if ( $("body").attr("class") == "")
{
$("body").addClass("class");
}
The issue I am having is that it deletes existing body classes already there. Instead, I would like to append to whatever body classes exist and not overwrite.
Use this:
$("body").addClass(newClass);
instead of
$("body").attr("class",newClass);
This is a setter: $("body").attr("class",newClass); which sets the class to the newClass and does not append it.
Use addClass instead of attr('class', newClass). The addClass also accepts a white-space separated list of class names, and correctly adds them.
$("body").addClass(newClass);
if ( $("body").attr("class") == "") // Makes no sense, since you have previously
{ // added `newClass`
$("body").addClass("class");
}
For documentation on addClass, see http://api.jquery.com/addClass/
.attr("class", newClass) is removing all existing classes. You should be using .addClass() instead:
$("body").addClass(newClass);
In addition, since you've just added a class to body, the code below will always be false:
if ( $("body").attr("class") == "") { }
Use addClass function instead - http://api.jquery.com/addClass/