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';
}
});
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];
}
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/
consider the following case (simplification):
<li class='dest_list' data-selval='A'><span>1</span></li>
<li class='dest_list' data-selval='B'><span>2</span></li>
<li class='dest_list' data-selval='C'><span>3</span></li>
Now I want to check if a variable exist in anyli. And I know I can do the following :
var needle = "D";
var found = false;
$('.dest_list').each(function(){
if($(this).data("selval") == needle)
found = true;
});
But what I wonder is can I do that using a selector? Something like :
if($(('.dest_list').data("selval") == needle)
Is there any possible way to do that?
You can write the attribute in the selector like this
$('.dest_list[data-selval="D"]')
or if you want to use a variable you can do this
$('.dest_list[data-selval="' + needle + '"]')
Documentation
You can use attribute selector to achieve that.
Try,
if($('.dest_list[data-selval="D"]').length > 0){
//found
}
You can use the attribute selector:
// Test for existence of element
if($(".dest_list[data-selval='D']").length) {
// li with selval A exists...
}
I'm creating a news page. I need to find out if there is set an anchor to an article. If not, I just show the latest article. An example URL with anchor is: example.com/news.php#article43
The HTML structure is:
<div>
<a name="article43"></a>
<h2>TITLE</h2>
<div class="news_content"></div>
</div>
And my JS is this:
var anchor = $(location).attr('href').split('#');
if(anchor[1]){
$('a[name=' + anchor[1] + ']').next('.news_content').show();
}else{
$('.news_content').first().show();
}
Something doesn't work.
next will only return the immediate sibling after the element, you probably want nextAll:
$('a[name=' + anchor[1] + ']').nextAll('.news_content').show();
or, if your HTML structure doesn't involve wrapping, ie:
<div>
<a name="article43"></a>
<h2>TITLE</h2>
<div class="news_content"></a>
<a name="article44"></a>
<h2>TITLE</h2>
<div class="news_content"></a>
</div>
You'd want: http://jsfiddle.net/AVg3y/
$('a[name=' + anchor[1] + ']').nextAll('.news_content').first().show();
Also, this is probably just a typo, but your HTML is malformed. It should be:
<div>
<a name="article43"></a>
<h2>TITLE</h2>
<div class="news_content"></div> //<-- oops
</div>
Try this (use siblings instead of next):
var anchor = location.href.split('#');
if(anchor[1]) {
$('a[name=' + anchor[1] + ']').siblings('.news_content').show();
} else {
$('.news_content').first().show();
}
You can get the hash by looking at window.location.hash. Use substring(1), to return everything after the # in the window.location.hash value.
if(window.location.hash) {
$('a[name=' + window.location.hash.substring(1) + ']').next('.news_content').show();
} else {
$('.news_content').first().show();
}
I solved the problem.
First: I ned to use nextAll() as many of you said.
Second: I included a CSS with jQuery (one that's only used when JS is enabled). I had to include this before the $(document).ready function. Else it was setting the news_content elements to display:none
Thanks to all who tried to help me.
All the answers have simlilar variations for hash, but none check to see if the hash has a matching element:
I suggest checking that the element exists as part of condition.
var contentToDisplay=$('.news_content').first();
if(anchor[1]){
var $link= $('a[name="' + anchor[1] + '"]');
contentToDisplay= $link.length ? $link.next().next('.news_content') : contentToDisplay;
}
contentToDisplay.show()
I have the following HTML snippet:
<span class="target">Change me <a class="changeme" href="#">now</a></span>
I'd like to change the text node (i.e. "Change me ") inside the span from jQuery, while leaving the nested <a> tag with all attributes etc. intact. My initial huch was to use .text(...) on the span node, but as it turns out this will replace the whole inner part with the passed textual content.
I solved this with first cloning the <a> tag, then setting the new text content of <span> (which will remove the original <a> tag), and finally appending the cloned <a> tag to my <span>. This works, but feels such an overkill for a simple task like this. Btw. I can't guarantee that there will be an initial text node inside the span - it might be empty, just like:
<span class="target"><a class="changeme" href="#">now</a></span>
I did a jsfiddle too. So, what would be the neat way to do this?
Try something like:
$('a.changeme').on('click', function() {
$(this).closest('.target').contents().not(this).eq(0).replaceWith('Do it again ');
});
demo: http://jsfiddle.net/eEMGz/
ref: http://api.jquery.com/contents/
Update:
I guess I read your question wrong, and you're trying to replace the text if it's already there and inject it otherwise. For this, try:
$('a.changeme').on('click', function() {
var
$tmp = $(this).closest('.target').contents().not(this).eq(0),
dia = document.createTextNode('Do it again ');
$tmp.length > 0 ? $tmp.replaceWith(dia) : $(dia).insertBefore(this);
});
Demo: http://jsfiddle.net/eEMGz/3/
You can use .contents():
//set the new text to replace the old text
var newText = 'New Text';
//bind `click` event handler to the `.changeme` elements
$('.changeme').on('click', function () {
//iterate over the nodes in this `<span>` element
$.each($(this).parent().contents(), function () {
//if the type of this node is undefined then it's a text node and we want to replace it
if (typeof this.tagName == 'undefined') {
//to replace the node we can use `.replaceWith()`
$(this).replaceWith(newText);
}
});
});
Here is a demo: http://jsfiddle.net/jasper/PURHA/1/
Some docs for ya:
.contents(): http://api.jquery.com/contents
.replaceWith(): http://api.jquery.com/replacewith
typeof: https://developer.mozilla.org/en/JavaScript/Reference/Operators/typeof
Update
var newText = 'New Text';
$('a').on('click', function () {
$.each($(this).parent().contents(), function () {
if (typeof this.tagName == 'undefined') {
//instead of replacing this node with the replacement string, just replace it with a blank string
$(this).replaceWith('');
}
});
//then add the replacement string to the `<span>` element regardless of it's initial state
$(this).parent().prepend(newText);
});
Demo: http://jsfiddle.net/jasper/PURHA/2/
You can try this.
var $textNode, $parent;
$('.changeme').on('click', function(){
$parent = $(this).parent();
$textNode= $parent.contents().filter(function() {
return this.nodeType == 3;
});
if($textNode.length){
$textNode.replaceWith('Content changed')
}
else{
$parent.prepend('New content');
}
});
Working demo - http://jsfiddle.net/ShankarSangoli/yx5Ju/8/
You step out of jQuery because it doesn't help you to deal with text nodes. The following will remove the first child of every <span> element with class "target" if and only if it exists and is a text node.
Demo: http://jsfiddle.net/yx5Ju/11/
Code:
$('span.target').each(function() {
var firstChild = this.firstChild;
if (firstChild && firstChild.nodeType == 3) {
firstChild.data = "Do it again";
}
});
This is not a perfect example I guess, but you could use contents function.
console.log($("span.target").contents()[0].data);
You could wrap the text into a span ... but ...
try this.
http://jsfiddle.net/Y8tMk/
$(function(){
var txt = '';
$('.target').contents().each(function(){
if(this.nodeType==3){
this.textContent = 'done ';
}
});
});
You can change the native (non-jquery) data property of the object. Updated jsfiddle here: http://jsfiddle.net/elgreg/yx5Ju/2/
Something like:
$('a.changeme3').click(function(){
$('span.target3').contents().get(0).data = 'Do it again';
});
The contents() gets the innards and the get(0) gets us back to the original element and the .data is now a reference to the native js textnode. (I haven't tested this cross browser.)
This jsfiddle and answer are really just an expanded explanation of the answer to this question:
Change text-nodes text
$('a.changeme').click(function() {
var firstNode= $(this).parent().contents()[0];
if( firstNode.nodeType==3){
firstNode.nodeValue='New text';
}
})
EDIT: not sure what layout rules you need, update to test only first node, otherwise adapt as needed