if links contains last part of window location - javascript

Trying to add a class to a parent of link that contains last part of window location for further styling.
the basic html would look like this
<li>
Some link
<ul>
<li class="subnavli">
Link Text
</li>
</ul>
</li>
and the js/jquery i'm trying to use is
function getLastSegmentOfPath(url) {
var matches = url.match(/\/([^\/]+)\/?$/);
if (matches) {
return matches[1];
}
return null;
}
var endPath = getLastSegmentOfPath(window.location.href);
$(".subnavli a").each(function(){
if ($(this).attr('href').contains(endPath)) {
$(this).parent().parent().parent().addClass('active5');
}
});
As you can probably guess, it's not working.

contains() was problem. Now should work. contains() function is something else: http://api.jquery.com/jquery.contains/ And, also there is contains selector, but that's another story...
function getLastSegmentOfPath(url) {
var matches = url.match(/\/([^\/]+)\/?$/);
if (matches) {
return matches[1];
}
return null;
}
endPath = getLastSegmentOfPath(window.location.href);
console.log(endPath);
$(".subnavli a").each(function(){
if ($(this).attr('href').indexOf(endPath)) {
$(this).parent().parent().prev('a').addClass('active5');
}
});
});
DEMO: http://jsfiddle.net/gvmhtLud/2/

Related

Check if href equals a certain value

Currently im looping through links in a page and checking if the link contains a string to determine the url. Heres my current code:
$( ".domain a" ).each( function () {
if ($(this).is(':contains("imgur")')) {
This can detect if the element contains the string "imgur", but because of this is a link goes to a site like slimgur.com, it will also return true.
How can I properly check that the url is, in this example, imgur.com or any of its subdomains (i.imgur.com & m.imgur.com) and that a url such as slimgur.com wont return true?
Rather than check the text, use the properties associated to an <a> tag like hostname.
$( ".domain a" ).filter(function(){
return this.hostname === 'imgur.com';
}).doSomething();
DEMO
This will do it:
$( ".domain a" ).each( function() {
var str = 'imgur';
if($(this)[0].hostname.split('.').indexOf(str) > -1) {
console.log('Found ' + str);
}
})
You could do something like: JS Fiddle
$('a').each(function () {
var url = "yahoo.com";
var anchor = $(this).attr('href');
var domain = url_domain(anchor);
if (url === domain) {
//Do something here
}
});
function url_domain(data) {
var a = document.createElement('a');
a.href = data;
return a.hostname;
}
url_domain() function found here: Extract hostname name from string

Changing href value from JavaScript

I have this example in JsFiddle.
http://jsfiddle.net/PtNfD/114/
Yahoo
Not working
$(document).ready (function () {
$('#changeMe'). click (function (e) {
var goLucky = Math.floor(Math.random()*12);
if (goLucky % 2 == 0) {
this.href = "http://www.google.com";
} else {
this.href = "http://www.hotmail.com";
}
});
});
The href change works in the first link, but not in the second. How can I make it work for both links??
The number of links in my page is dynamic, because I create the links with PHP, so I need the href change to work in all generated links.
id attributes must be unique. You should convert the value changeMe to a classname for use on multiple elements. Then your existing code should work:
Yahoo
Not working
$(document).ready (function () {
$('.changeMe'). click (function (e) {
var goLucky = Math.floor(Math.random()*12);
if (goLucky % 2 == 0) {
this.href = "http://www.google.com";
} else {
this.href = "http://www.hotmail.com";
}
});
});
Optionally, you could add a unique id to the second anchor tag and modify the JavaScript code accordingly.
You cannot use an ID on two different elements in HTML. You need to asign each of those a different ID or the same class instead and then apply your href change on each of the IDs, or the class
IDs should be used once per webpage. Classes can be used more plentifully. Remember your specificity. Use class instead of id: http://jsfiddle.net/PtNfD/115/
Yahoo
Not working
$(document).ready (function () {
$('.changeMe'). click (function (e) {
var goLucky = Math.floor(Math.random()*12);
if (goLucky % 2 == 0) {
this.href = "http://www.google.com";
} else {
this.href = "http://www.hotmail.com";
}
});
});

How to remove this li element from an ng-repeat?

Below in my list, one of the divs at the bottom has a removePortfolio function. This function's job is to activate the ng-hide="tickerRemoved" but only for that 1 list item, not all the list items.
HTML Gist: https://gist.github.com/leongaban/cf72e5d0229155dd011f
Directive Gist: https://gist.github.com/leongaban/22a8feb9dbeea0b90135
<ul ng-show="loadingTickersDone" class="tickers-list">
<li class="ticker-li"
ng-repeat="ticker in tickers"
ng-hide="tickerRemoved"
ng-class="{'selected':toggleTicker.item == $index}"
ng-mouseleave="hideTickerOptions()">
<div class="ticker"
ng-click="toggleTicker.item = $index;
selectTicker(ticker.ticker);
revealTickerOptions()">
{{ticker.ticker}}
</div>
<div class="add-to-portfolio"
ng-show="tickerOptions"
ng-mouseleave="hideTickerOptions()">
<div ng-show="addOption"
ng-click="addPortfolio(ticker.ticker)">+ Portfolio</div>
<div ng-show="removeOption"
ng-click="removePortfolio(ticker.ticker)">- Portfolio</div>
</div>
</li>
</ul>
Here is the remove function in the directive:
var vs = $scope;
vs.removePortfolio = function(ticker) {
this.tickerOptions = false;
ApiFactory.deleteWatchList(ticker).then(function(data) {
showMessage(ticker+' removed from portfolio!', data.data.status);
this.tickerRemoved = true;
});
};
I get an error with this.tickerRemoved = true; I think this is because the scope is lower in the chain?
For example, I'm using this in this function and it works fine because the function is higher in the markup/scope:
vs.revealTickerOptions = function() {
this.tickerOptions = true;
if (tickerView === 'all') {
this.addOption = true;
this.removeOption = false;
}
else if (tickerView === 'port') {
this.addOption = false;
this.removeOption = true;
}
};
How would I remove just the 1 <li class="ticker-li" item when clicking the removePortfolio() function?
ng-hide="tickerRemoved" should be ng-hide="ticker.tickerRemoved" since tickerRemoved is a property of a specific ticker.
Same with ng-show="tickerOptions"... should be ng-show="ticker.tickerOptions" from the looks of it.
ng-click="removePortfolio(ticker.ticker)"> should be ng-click="removePortfolio(ticker)"> since you probably want to pass the entire ticker object.
After that, you will need to update your remove ticker function, something like this should work:
vs.removePortfolio = function(tickerObject) {
var ticker = tickerObject.ticker
tickerObject.tickerOptions = false;
ApiFactory.deleteWatchList(ticker).then(function(data) {
showMessage(ticker+' removed from portfolio!', data.data.status);
tickerObject.tickerRemoved = true;
});
};
As a general observation, it looks like you are leaning on this too much. this can be a very confusing keyword and should only be used (in my opinion) when there is both a good reason to do so and doing so will not cause confusion during later code maintenance.

Check if class exists somewhere in parent

I want to check if a class exsits somewhere in one of the parent elements of an element.
I don't want to use any library, just vanilla JS.
In the examples below it should return true if the element in question resides somewhere in the childs of an element with "the-class" as the class name.
I think it would be something like this with jQuery:
if( $('#the-element').parents().hasClass('the-class') ) {
return true;
}
So this returns true:
<div>
<div class="the-class">
<div id="the-element"></div>
</div>
</div>
So does this:
<div class="the-class">
<div>
<div id="the-element"></div>
</div>
</div>
...but this returns false:
<div>
<div class="the-class">
</div>
<div id="the-element"></div>
</div>
You can use the closest() method of Element that traverses parents (heading toward the document root) of the Element until it finds a node that matches the provided selectorString. Will return itself or the matching ancestor. If no such element exists, it returns null.
You can convert the returned value into boolean
const el = document.getElementById('div-03');
const r1 = el.closest("#div-02");
console.log(Boolean(r1));
// returns the element with the id=div-02
const r2 = el.closest("#div-not-exists");
console.log(Boolean(r2));
<article>
<div id="div-01">Here is div-01
<div id="div-02">Here is div-02
<div id="div-03">Here is div-03</div>
</div>
</div>
</article>
You'll have to do it recursively :
// returns true if the element or one of its parents has the class classname
function hasSomeParentTheClass(element, classname) {
if (element.className.split(' ').indexOf(classname)>=0) return true;
return element.parentNode && hasSomeParentTheClass(element.parentNode, classname);
}
Demonstration (open the console to see true)
You can use some and contains to achieve the result:
function hasParentWithMatchingSelector (target, selector) {
return [...document.querySelectorAll(selector)].some(el =>
el !== target && el.contains(target)
)
}
// usage
hasParentWithMatchingSelector(myElement, '.some-class-name');
The fiddle
The code
function hasClass(element, className) {
var regex = new RegExp('\\b' + className + '\\b');
do {
if (regex.exec(element.className)) {
return true;
}
element = element.parentNode;
} while (element);
return false;
}
OR
function hasClass(element, className) {
do {
if (element.classList && element.classList.contains(className)) {
return true;
}
element = element.parentNode;
} while (element);
return false;
}
I'm ok with the function that Denys Séguret posted, it looks elegant and I like it.
I just tweaked a little bit that function since if the class specified in the parameter, is not present in the whole DOM, it fails when the recursion reaches the document object because is true that we control if the element has the parent node (in the last line, and when the document is the element the parent node is null) but before we execute the previous line, and when the element is the document, document.className is undefined and it fails, so the control must be moved to the top.
function hasSomeParentTheClass(element, classname) {
//
// If we are here we didn't find the searched class in any parents node
//
if (!element.parentNode) return false;
//
// If the current node has the class return true, otherwise we will search
// it in the parent node
//
if (element.className.split(' ').indexOf(classname)>=0) return true;
return hasSomeParentTheClass(element.parentNode, classname);
}
I believe if( $('#the-element').parents('.the-class').length ) to be more efficient, but perhaps not as human-readable; which, with querySelector in the picture, could be replaced with the following method:
function hasParent(element, parentSelector) {
var potentialParents = document.querySelectorAll(parentSelector);
for(i in potentialParents) if(potentialParents[i].contains(element))
return potentialParents[i];
return false;
}
That'd give you the ability to do:
var elm = document.getElementById('the-element');
if(hasParent(elm, '.the-class')) return true;
Try the closest() function - For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. Refer to the Official Docs here.
Another alternative for some those who like this style for modern/polyfilled browsers.
const hasClass = (element, className) => {
return element.classList.contains(className);
};
const hasParent = (element, className) => {
if (!element.parentNode) {
return false;
}
if (hasClass(element, className)) {
return true;
}
return hasParent(element.parentNode, className)
};
Working demo:
const hasClass = (element, className) => {
return element.classList.contains(className);
};
const hasParent = (element, className) => {
if (!element.parentNode) {
return false;
}
if (hasClass(element, className)) {
return true;
}
return hasParent(element.parentNode, className)
};
/* Demo Code, can ignore */
const child = document.getElementById('child');
const orphan = document.getElementById('orphan');
const output = document.getElementById('output');
const log = `child has parent? ${hasParent(child, 'list')}
orphan has parent? ${hasParent(orphan, 'list')}
`
output.innerText = log;
#output {
margin-top: 50px;
background: black;
color: red;
padding: 20px;
}
<div>
<ul class="list">
<li>
<a id="child" href="#">i have a parent</a>
</li>
</ul>
</div>
<div>
<ul>
<li>
<a id="orphan" href="#">im an orphan</a>
</li>
</ul>
</div>
<div id="output"></div>
My example for Vanilla JS, it's use a vanilla equivalent of parents() from jQuery
var htmlElement = <htmlElement>,
parents = [],
classExist;
while (htmlElement = htmlElement.parentNode.closest(<parentSelector>)) {
parents.push(htmlElement);
}
classExist = (parents > 0);
So your selector just to be a .className
And just check if parent is > 0
Because ID must be unique on document context, you could just use instead:
return !!document.querySelector('.the-class #the-element');
If you want to include element itself, you can use:
return !!document.querySelector('.the-class #the-element, #the-element.the-class');

Can't get innerHTML of tag on IE8

I am trying to get the innerhtml of class name current_page_item[0]... And this is working fine in FF and even in IE9 also. But in IE 8 it seems to be some javascript error in line" var classelem=document.getElementsByClassName('current_page_item')[0].innerHTML;.
I tried to put alert after the above line. But it is not displaying the message "Hello again".
Any idea how to solve the browser issue for this? Is it something that document.getElementsByClassName wont work in IE8?
<html>
<head>
<script type="text/javascript">
function updatesidebar()
{
alert("Hello");
var classelem=document.getElementsByClassName('current_page_item')[0].innerHTML;
alert("Hello again");
}
</script>
</head>
<body>
<div id="main">
<div class="menu_main">
<ul class='mainmenu' id='root'>
<li>Home</li>
<li>Solutions
</li><li>Services</li>
<li>About Us</li>
<li>News and Events</li>
<li>Careers</li>
<li>Contact Us</li>
</ul>
</div>
</div>
<script type="text/javascript">
window.onload=updatesidebar();
</script>
</body>
</html>
Not all browsers natively support getElementsByClassName although the situation is improving. You could use a function which checks for the native implementation and uses it if found or else grabs all the elements and checks each one for the classname, returning an array of those that match.
function getElementsByClassName( className, context ) {
//the context is the container we will confine our search to (optional)
context = context || document;
//use native implimentation if it exists
if( context.getElementsByClassName ) {
return context.getElementsByClassName( className ); //returns a nodeList
}
//we have to do it ourselves if we get here
var candidates = context.getElementsByTagName( '*' );
var found = [];
//regular expression to match the classname as per comments
var rxp = new RegExp( "(?:^|\\s)" + className + "(?:\\s|$)");
for( var i = 0, l = candidates.length; i < l; i++ ) {
if( rxp.test( className ) {
found.push( candidates[i] );
}
}
return found; //returns an array of nodes
}
getElementsByClassName is not compatible in IE8. it's part of HTML5
Change:
window.onload=updatesidebar();
to:
window.onload=updatesidebar;
The way you have it just now will call the function immediately rather than when the page is loaded.
getElementsByClassName is not a JS native function you must refer to any library including it
you don't have to change the code, but you may add that function if not exists... ;)
if (typeof document.getElementsByClassName!='function') {
document.getElementsByClassName = function() {
var elms = document.getElementsByTagName('*');
var ei = new Array();
for (i=0;i<elms.length;i++) {
if (elms[i].getAttribute('class')) {
ecl = elms[i].getAttribute('class').split(' ');
for (j=0;j<ecl.length;j++) {
if (ecl[j].toLowerCase() == arguments[0].toLowerCase()) {
ei.push(elms[i]);
}
}
} else if (elms[i].className) {
ecl = elms[i].className.split(' ');
for (j=0;j<ecl.length;j++) {
if (ecl[j].toLowerCase() == arguments[0].toLowerCase()) {
ei.push(elms[i]);
}
}
}
}
return ei;
}
}

Categories

Resources