Custom Javascript href selector - javascript

With jquery it's rather easy to use a selector which url starts with x. Something like that:
$("a[href*=#test]").click(function(e) {
e.preventDefault();
alert('works');
});
Is there equivalent to it in pure javascript? Or what would be the easiest way to do it?
I have found getElementsByName and getElementsByClassName but what about this case?

I think querySelectorAll should do the trick if you don't need to support IE < 8 (http://caniuse.com/queryselector)

There's no equivalent in the older Javascript spec, so you can't use querySelectorAll, and still support older browsers like <IE8.
What you'd have to do is use getElementsByTagName, and then filter the results by checking each one's href property. If you check the JQuery source, I think you'll find it does just that, more or less.
You can always use newer features like querySelectorAll, and include a "polyfill" to add support for older browsers. Here's an example.
if (!document.querySelectorAll) {
document.querySelectorAll = function(selector) {
var doc = document,
head = doc.documentElement.firstChild,
styleTag = doc.createElement('STYLE');
head.appendChild(styleTag);
doc.__qsaels = [];
styleTag.styleSheet.cssText = selector + "{x:expression(document.__qsaels.push(this))}";
window.scrollBy(0, 0);
return doc.__qsaels;
}
}

This article has some great information on this.
http://remysharp.com/2013/04/19/i-know-jquery-now-what/
Pure Javascript
var $ = document.querySelectorAll.bind(document);
Element.prototype.on = Element.prototype.addEventListener;
$('#somelink')[0].on('touchstart', handleTouch);
But I don't think it supports old IE and you may not be able to do the selector your desire
However,
If your just looking for something lightweight you can use the sizzle engine on its own, without jquery.
Only weighs 4k.

//Only searches anchor tags
function getElementsByHref(href) {
var els = document.getElementsByTagName("a");
var result = [];
for (i=0;i<els.length;i++) {
if (els[i].getAttribute("href") == href) result.push(els[i]);
}
return result;
}

You can do it with document.querySelector (or querySelectorAll)
If you want a link whose href starts with 'test' you can use -
document.querySelectorAll("a[href^=test]');

var hyperlinks = document.getElementsByTagName("a") would return all hyerlinks within your document. You can then loop over those results and for each element check the value of the href attribute via element.getAttribute("href") and check if that string value starts with the desired string, if it does then bind a click event to that element.

You can also use this procedure:
var a = document.getElementsByTagName('a');
for (var i=0; i<a.length; i++){
if ((a[i].id && a[i].id.toLowerCase().indexOf('test') !== 0) {
continue; // id not starts with 'test'
}
if (a[i].addEventListener) {
a[i].addEventListener('click', handler, false);
} else {
a[i].attachEvent('onclick', handler);
}
}
function handler(e){
e = e || window.event; // for IE8/7 backward compatibility
if (e.preventDefault) {
e.preventDefault();
} else {
event.returnValue = false; // for IE8/7 backward compatibility
}
alert('works');
}
http://jsfiddle.net/VcVpM/19/ (code)
http://jsfiddle.net/VcVpM/19/show (result page)

Related

How to make document.querySelector work in IE6

I work on a website and I got a javascript function that doesn't work in Internet Explorer 6.
I know
document.querySelector(selector)
only work in Internet Explorer 8+
What could I do to make it work in IE6?
(I don't try to make it work for the fun of it ;) )
I strongly encourage you not to try to support IE6 any longer.
But you can add document.querySelector and document.querySelectorAll using this very clever trick from an Ajaxian article. The article actually gets it a bit wrong, it adds something called querySelector that does querySelectorAll instead. I've fixed the name here:
/*#cc_on
if (!document.querySelectorAll)
document.querySelectorAll = function(selector)
{
var head = document.documentElement.firstChild;
var styleTag = document.createElement("STYLE");
head.appendChild(styleTag);
document.__qsResult = [];
styleTag.styleSheet.cssText = selector + "{x:expression(document.__qsResult.push(this))}";
window.scrollBy(0, 0);
head.removeChild(styleTag);
var result = [];
for (var i in document.__qsResult)
result.push(document.__qsResult[i]);
return result;
}
#*/
Although I would never countenance using for-in like that; details and alternatives in this other answer.
And by inference, querySelector:
/*#cc_on
if (!document.querySelector)
document.querySelector = function(selector)
{
var head = document.documentElement.firstChild;
var styleTag = document.createElement("STYLE");
head.appendChild(styleTag);
document.__qsResult = [];
styleTag.styleSheet.cssText = selector + "{x:expression(document.__qsResult.push(this))}";
window.scrollBy(0, 0);
head.removeChild(styleTag);
// Return first result only
return document.__qsResult[0] || null;
}
#*/
Note that neither of the above adds Element#querySelector or Element#querySelectorAll (the versions that look only within an element), just document.querySelector and document.querySelectorAll. And you can't add the Element versions on IE6 without adding them to each individual element, since IE6 doesn't support element prototypes.
You could use a polyfill, like this one, however still using IE6, is the IT analogue of necromancy.
The mentioned polyfill is based on polyfill.js, which can be found here, this provides polyfills for a lot of ECMA 5 functions.
I will post the current state of the script, maybe it will useful in the future (though I really hope, it won't be :) ):
if (!document.querySelectorAll) {
document.querySelectorAll = function (selectors) {
var style = document.createElement('style'), elements = [], element;
document.documentElement.firstChild.appendChild(style);
document._qsa = [];
style.styleSheet.cssText = selectors +
'{x-qsa:expression(document._qsa && document._qsa.push(this))}';
window.scrollBy(0, 0);
style.parentNode.removeChild(style);
while (document._qsa.length) {
element = document._qsa.shift();
element.style.removeAttribute('x-qsa');
elements.push(element);
}
document._qsa = null;
return elements;
};
}
if (!document.querySelector) {
document.querySelector = function (selectors) {
var elements = document.querySelectorAll(selectors);
return (elements.length) ? elements[0] : null;
};
}

JavaScript selector for data-event?

Is there a way to select an element based on the data-event attribute?
Here is what I have:
<button data-event="5456293788" class="id-button-yes greenBtn list-buy-buttons">Buy now!</button>
Looking for something like:
document.getElementByDataEvent('5456293788')
Possible?
Something like this?
document.querySelector("button[data-event='5456293788']");
See in JSFiddle
It has quite a wide browser support (even IE 8 supports it)
Use the attribute selector
http://jsfiddle.net/QTNzf/
JS
document.querySelector('button[data-event="5456293788"]' );
CSS
button[data-devent="5456293788"] {
background-color: #eee;
}
The attribute selector does spring to mind, and you don't need jQuery to use that.
It probably won't work on older browsers, though.
If you really want, you can add a getElementsByDataEvent to the document object (not sure if all browsers allow this):
document.getElementsByDataEvent = function(dataEvent)
{
return document.querySelectorAll('[data-event="'+dataEvent+'"]');
};
But as you can see, this is a bit unnecessary, since it's just returning the return-value of a querySelectorAll call. What's more, if you use querySelectorAll directly, you can do something like this
document.querySelectorAll('a[data-event="foo"]');//only links will be retured
//or, with some other data-* thing, along the lines of:
document.querySelectorAll('[class="greenBtn"]');
Use the attribute equals selector in jQuery:
$('[data-event="5456293788"]')
or with document.querySelectorAll:
document.querySelectorAll('[data-event="5456293788"]');
For backwards compatibility, you'd have to iterate through all the elements checking the attribute values. This is a case where a library such as jQuery really helps.
backwards compatible raw js:
function getElementsByAttr(attr, val) {
var nodes,
node,
i,
ret;
val = '' + val;
nodes = document.getElementsByTagName('*');
ret = [];
for (i = 0; i < nodes.length; i += 1) {
node = nodes[i];
if (node.getAttribute(attr) === val) {
ret.push(node);
}
}
return ret;
}
de = getElementsByAttr('data-event', '5456293788');

Getting element by a custom attribute using JavaScript

I have an XHTML page where each HTML element has a unique custom attribute, like this:
<div class="logo" tokenid="14"></div>
I need a way to find this element by ID, similar to document.getElementById(), but instead of using a general ID, I want to search for the element using my custom "tokenid" attribute. Something like this:
document.getElementByTokenId('14');
Is that possible? If yes - any hint would be greatly appreciated.
Thanks.
It is not good to use custom attributes in the HTML. If any, you should use HTML5's data attributes.
Nevertheless you can write your own function that traverses the tree, but that will be quite slow compared to getElementById because you cannot make use of any index:
function getElementByAttribute(attr, value, root) {
root = root || document.body;
if(root.hasAttribute(attr) && root.getAttribute(attr) == value) {
return root;
}
var children = root.children,
element;
for(var i = children.length; i--; ) {
element = getElementByAttribute(attr, value, children[i]);
if(element) {
return element;
}
}
return null;
}
In the worst case, this will traverse the whole tree. Think about how to change your concept so that you can make use browser functions as much as possible.
In newer browsers you use of the querySelector method, where it would just be:
var element = document.querySelector('[tokenid="14"]');
This will be much faster too.
Update: Please note #Andy E's comment below. It might be that you run into problems with IE (as always ;)). If you do a lot of element retrieval of this kind, you really should consider using a JavaScript library such as jQuery, as the others mentioned. It hides all these browser differences.
<div data-automation="something">
</div>
document.querySelector("div[data-automation]")
=> finds the div
document.querySelector("div[data-automation='something']")
=> finds the div with a value
If you're using jQuery, you can use some of their selector magic to do something like this:
$('div[tokenid=14]')
as your selector.
You can accomplish this with JQuery:
$('[tokenid=14]')
Here's a fiddle for an example.
If you're willing to use JQuery, then:
var myElement = $('div[tokenid="14"]').get();
Doing this with vanilla JavaScript will do the trick:
const something = document.querySelectorAll('[data-something]')
Use this more stable Function:
function getElementsByAttribute(attr, value) {
var match = [];
/* Get the droids we are looking for*/
var elements = document.getElementsByTagName("*");
/* Loop through all elements */
for (var ii = 0, ln = elements.length; ii < ln; ii++) {
if (elements[ii].nodeType === 1){
if (elements[ii].name != null){
/* If a value was passed, make sure it matches the elements */
if (value) {
if (elements[ii].getAttribute(attr) === value)
match.push(elements[ii]);
} else {
/* Else, simply push it */
match.push(elements[ii]);
}
}
}
}
return match;
};

How to Get Element By Class in JavaScript?

I want to replace the contents within a html element so I'm using the following function for that:
function ReplaceContentInContainer(id,content) {
var container = document.getElementById(id);
container.innerHTML = content;
}
ReplaceContentInContainer('box','This is the replacement text');
<div id='box'></div>
The above works great but the problem is I have more than one html element on a page that I want to replace the contents of. So I can't use ids but classes instead. I have been told that javascript does not support any type of inbuilt get element by class function. So how can the above code be revised to make it work with classes instead of ids?
P.S. I don't want to use jQuery for this.
This code should work in all browsers.
function replaceContentInContainer(matchClass, content) {
var elems = document.getElementsByTagName('*'), i;
for (i in elems) {
if((' ' + elems[i].className + ' ').indexOf(' ' + matchClass + ' ')
> -1) {
elems[i].innerHTML = content;
}
}
}
The way it works is by looping through all of the elements in the document, and searching their class list for matchClass. If a match is found, the contents is replaced.
jsFiddle Example, using Vanilla JS (i.e. no framework)
Of course, all modern browsers now support the following simpler way:
var elements = document.getElementsByClassName('someClass');
but be warned it doesn't work with IE8 or before. See http://caniuse.com/getelementsbyclassname
Also, not all browsers will return a pure NodeList like they're supposed to.
You're probably still better off using your favorite cross-browser library.
document.querySelectorAll(".your_class_name_here");
That will work in "modern" browsers that implement that method (IE8+).
function ReplaceContentInContainer(selector, content) {
var nodeList = document.querySelectorAll(selector);
for (var i = 0, length = nodeList.length; i < length; i++) {
nodeList[i].innerHTML = content;
}
}
ReplaceContentInContainer(".theclass", "HELLO WORLD");
If you want to provide support for older browsers, you could load a stand-alone selector engine like Sizzle (4KB mini+gzip) or Peppy (10K mini) and fall back to it if the native querySelector method is not found.
Is it overkill to load a selector engine just so you can get elements with a certain class? Probably. However, the scripts aren't all that big and you will may find the selector engine useful in many other places in your script.
A Simple and an easy way
var cusid_ele = document.getElementsByClassName('custid');
for (var i = 0; i < cusid_ele.length; ++i) {
var item = cusid_ele[i];
item.innerHTML = 'this is value';
}
I'm surprised there are no answers using Regular Expressions. This is pretty much Andrew's answer, using RegExp.test instead of String.indexOf, since it seems to perform better for multiple operations, according to jsPerf tests.
It also seems to be supported on IE6.
function replaceContentInContainer(matchClass, content) {
var re = new RegExp("(?:^|\\s)" + matchClass + "(?!\\S)"),
elems = document.getElementsByTagName('*'), i;
for (i in elems) {
if (re.test(elems[i].className)) {
elems[i].innerHTML = content;
}
}
}
replaceContentInContainer("box", "This is the replacement text.");
If you look for the same class(es) frequently, you can further improve it by storing the (precompiled) regular expressions elsewhere, and passing them directly to the function, instead of a string.
function replaceContentInContainer(reClass, content) {
var elems = document.getElementsByTagName('*'), i;
for (i in elems) {
if (reClass.test(elems[i].className)) {
elems[i].innerHTML = content;
}
}
}
var reBox = /(?:^|\s)box(?!\S)/;
replaceContentInContainer(reBox, "This is the replacement text.");
This should work in pretty much any browser...
function getByClass (className, parent) {
parent || (parent=document);
var descendants=parent.getElementsByTagName('*'), i=-1, e, result=[];
while (e=descendants[++i]) {
((' '+(e['class']||e.className)+' ').indexOf(' '+className+' ') > -1) && result.push(e);
}
return result;
}
You should be able to use it like this:
function replaceInClass (className, content) {
var nodes = getByClass(className), i=-1, node;
while (node=nodes[++i]) node.innerHTML = content;
}
var elems = document.querySelectorAll('.one');
for (var i = 0; i < elems.length; i++) {
elems[i].innerHTML = 'content';
};
I assume this was not a valid option when this was originally asked, but you can now use document.getElementsByClassName('');. For example:
var elements = document.getElementsByClassName(names); // or:
var elements = rootElement.getElementsByClassName(names);
See the MDN documentation for more.
There are 3 different ways to get elements by class in javascript. But here for your query as you have multiple elements with the same class names you can use 2 methods:
getElementsByClassName Method - It returns all the elements with the specified class present in the document or within the parent element which called it.
function ReplaceContentInContainer(className, content) {
var containers = document.getElementsByClassName(className);
for (let i = 0; i < containers.length; i++) {
containers[i].innerHTML = content;
}
}
ReplaceContentInContainer('box', 'This is the replacement text');
<div class='box'></div>
querySelectorAll Method - It select element on the basic of CSS selectors. Pass your CSS class to it with a dot and it will return all the element having specified class as an array-like object.
function ReplaceContentInContainer(className, content) {
var containers = document.querySelectorAll(`.${className}`);
for (let i = 0; i < containers.length; i++) {
containers[i].innerHTML = content;
}
}
ReplaceContentInContainer('box', 'This is the replacement text');
<div class='box'></div>
I think something like:
function ReplaceContentInContainer(klass,content) {
var elems = document.getElementsByTagName('*');
for (i in elems){
if(elems[i].getAttribute('class') == klass || elems[i].getAttribute('className') == klass){
elems[i].innerHTML = content;
}
}
}
would work
jQuery handles this easy.
let element = $(.myclass);
element.html("Some string");
It changes all the .myclass elements to that text.
When some elements lack ID, I use jQuery like this:
$(document).ready(function()
{
$('.myclass').attr('id', 'myid');
});
This might be a strange solution, but maybe someone find it useful.

Get class list for element with jQuery

Is there a way in jQuery to loop through or assign to an array all of the classes that are assigned to an element?
ex.
<div class="Lorem ipsum dolor_spec sit amet">Hello World!</div>
I will be looking for a "special" class as in "dolor_spec" above. I know that I could use hasClass() but the actual class name may not necessarily be known at the time.
You can use document.getElementById('divId').className.split(/\s+/); to get you an array of class names.
Then you can iterate and find the one you want.
var classList = document.getElementById('divId').className.split(/\s+/);
for (var i = 0; i < classList.length; i++) {
if (classList[i] === 'someClass') {
//do something
}
}
jQuery does not really help you here...
var classList = $('#divId').attr('class').split(/\s+/);
$.each(classList, function(index, item) {
if (item === 'someClass') {
//do something
}
});
Why has no one simply listed.
$(element).attr("class").split(/\s+/);
EDIT: Split on /\s+/ instead of ' ' to fix #MarkAmery's objection. (Thanks #YashaOlatoto.)
On supporting browsers, you can use DOM elements' classList property.
$(element)[0].classList
It is an array-like object listing all of the classes the element has.
If you need to support old browser versions that don't support the classList property, the linked MDN page also includes a shim for it - although even the shim won't work on Internet Explorer versions below IE 8.
Here is a jQuery plugin which will return an array of all the classes the matched element(s) have
;!(function ($) {
$.fn.classes = function (callback) {
var classes = [];
$.each(this, function (i, v) {
var splitClassName = v.className.split(/\s+/);
for (var j = 0; j < splitClassName.length; j++) {
var className = splitClassName[j];
if (-1 === classes.indexOf(className)) {
classes.push(className);
}
}
});
if ('function' === typeof callback) {
for (var i in classes) {
callback(classes[i]);
}
}
return classes;
};
})(jQuery);
Use it like
$('div').classes();
In your case returns
["Lorem", "ipsum", "dolor_spec", "sit", "amet"]
You can also pass a function to the method to be called on each class
$('div').classes(
function(c) {
// do something with each class
}
);
Here is a jsFiddle I set up to demonstrate and test http://jsfiddle.net/GD8Qn/8/
Minified Javascript
;!function(e){e.fn.classes=function(t){var n=[];e.each(this,function(e,t){var r=t.className.split(/\s+/);for(var i in r){var s=r[i];if(-1===n.indexOf(s)){n.push(s)}}});if("function"===typeof t){for(var r in n){t(n[r])}}return n}}(jQuery);
You should try this one:
$("selector").prop("classList")
It returns a list of all current classes of the element.
var classList = $(element).attr('class').split(/\s+/);
$(classList).each(function(index){
//do something
});
$('div').attr('class').split(' ').each(function(cls){ console.log(cls);})
Update:
As #Ryan Leonard pointed out correctly, my answer doesn't really fix the point I made my self... You need to both trim and remove double spaces with (for example) string.replace(/ +/g, " ").. Or you could split the el.className and then remove empty values with (for example) arr.filter(Boolean).
const classes = element.className.split(' ').filter(Boolean);
or more modern
const classes = element.classList;
Old:
With all the given answers, you should never forget to user .trim() (or $.trim())
Because classes gets added and removed, it can happen that there are multiple spaces between class string.. e.g. 'class1 class2 class3'..
This would turn into ['class1', 'class2','','','', 'class3']..
When you use trim, all multiple spaces get removed..
Might this can help you too. I have used this function to get classes of childern element..
function getClickClicked(){
var clickedElement=null;
var classes = null;<--- this is array
ELEMENT.on("click",function(e){//<-- where element can div,p span, or any id also a class
clickedElement = $(e.target);
classes = clickedElement.attr("class").split(" ");
for(var i = 0; i<classes.length;i++){
console.log(classes[i]);
}
e.preventDefault();
});
}
In your case you want doler_ipsum class u can do like this now calsses[2];.
Thanks for this - I was having a similar issue, as I'm trying to programatically relate objects will hierarchical class names, even though those names might not necessarily be known to my script.
In my script, I want an <a> tag to turn help text on/off by giving the <a> tag [some_class] plus the class of toggle, and then giving it's help text the class of [some_class]_toggle. This code is successfully finding the related elements using jQuery:
$("a.toggle").toggle(function(){toggleHelp($(this), false);}, function(){toggleHelp($(this), true);});
function toggleHelp(obj, mode){
var classList = obj.attr('class').split(/\s+/);
$.each( classList, function(index, item){
if (item.indexOf("_toggle") > 0) {
var targetClass = "." + item.replace("_toggle", "");
if(mode===false){$(targetClass).removeClass("off");}
else{$(targetClass).addClass("off");}
}
});
}
Try This. This will get you the names of all the classes from all the elements of document.
$(document).ready(function() {
var currentHtml="";
$('*').each(function() {
if ($(this).hasClass('') === false) {
var class_name = $(this).attr('class');
if (class_name.match(/\s/g)){
var newClasses= class_name.split(' ');
for (var i = 0; i <= newClasses.length - 1; i++) {
if (currentHtml.indexOf(newClasses[i]) <0) {
currentHtml += "."+newClasses[i]+"<br>{<br><br>}<br>"
}
}
}
else
{
if (currentHtml.indexOf(class_name) <0) {
currentHtml += "."+class_name+"<br>{<br><br>}<br>"
}
}
}
else
{
console.log("none");
}
});
$("#Test").html(currentHtml);
});
Here is the working example: https://jsfiddle.net/raju_sumit/2xu1ujoy/3/
For getting the list of classes applied to element we can use
$('#elementID').prop('classList')
For adding or removing any classes we can follow as below.
$('#elementID').prop('classList').add('yourClassName')
$('#elementID').prop('classList').remove('yourClassName')
And for simply checking if the class is present or not we can use hasClass
I had a similar issue, for an element of type image. I needed to check whether the element was of a certain class. First I tried with:
$('<img>').hasClass("nameOfMyClass");
but I got a nice "this function is not available for this element".
Then I inspected my element on the DOM explorer and I saw a very nice attribute that I could use: className. It contained the names of all the classes of my element separated by blank spaces.
$('img').className // it contains "class1 class2 class3"
Once you get this, just split the string as usual.
In my case this worked:
var listOfClassesOfMyElement= $('img').className.split(" ");
I am assuming this would work with other kinds of elements (besides img).
Hope it helps.
javascript provides a classList attribute for a node element in dom. Simply using
element.classList
will return a object of form
DOMTokenList {0: "class1", 1: "class2", 2: "class3", length: 3, item: function, contains: function, add: function, remove: function…}
The object has functions like contains, add, remove which you can use
A bit late, but using the extend() function lets you call "hasClass()" on any element, e.g.:
var hasClass = $('#divId').hasClass('someClass');
(function($) {
$.extend({
hasClass: new function(className) {
var classAttr = $J(this).attr('class');
if (classAttr != null && classAttr != undefined) {
var classList = classAttr.split(/\s+/);
for(var ix = 0, len = classList.length;ix < len;ix++) {
if (className === classList[ix]) {
return true;
}
}
}
return false;
}
}); })(jQuery);
The question is what Jquery is designed to do.
$('.dolor_spec').each(function(){ //do stuff
And why has no one given .find() as an answer?
$('div').find('.dolor_spec').each(function(){
..
});
There is also classList for non-IE browsers:
if element.classList.contains("dolor_spec") { //do stuff

Categories

Resources