How to make document.querySelector work in IE6 - javascript

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;
};
}

Related

JS HTML Object, search for elements who's classes contain

I'm generating some HTML from JSON, which leaves me with an HTML object with a dynamic amount of children, depends on one the user and if they change the JSON.
I need to keep a reference to certain elements depending on the classes, so the user may change the name of the classes, but they will need to have certain keywords, so, for example, I want to keep a reference to marvLightbox__close.
Someone could change this to something like something__close, so how can I search this HTML object's children for just close?
I have not yet appended this object to the DOM, it's just in memory.
P.S. NO JQUERY!
Edit
Found out I can use this, but I feel like it's cheating a bit! Plus I need to support IE8...
document.querySelectorAll('[class*=-img]')
Edit 2
The Polyfill actually isn't too many lines, so it's not too bad after all...
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;
};
}
Found out I can use this, but I feel like it's cheating a bit! Plus I need to support IE8...
document.querySelectorAll('[class*=-img]')
The Polyfill actually isn't too many lines, so it's not too bad after all...
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;
};
}

Custom Javascript href selector

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)

getElementsByClassName() doesn't work in old Internet Explorers like IE6, IE7, IE8

The following code:
var borderTds = document.getElementsByClassName('leftborder');
gives me an error message in Internet Explorer 6, 7 and 8:
Object does not support this method
How can I select elements by their class in these browsers?
I prefer not to use JQuery.
IE6, Netscape 6+, Firefox, and Opera 7+ copy the following script in your page:
document.getElementsByClassName = function(cl) {
var retnode = [];
var elem = this.getElementsByTagName('*');
for (var i = 0; i < elem.length; i++) {
if((' ' + elem[i].className + ' ').indexOf(' ' + cl + ' ') > -1) retnode.push(elem[i]);
}
return retnode;
};
This solution may help. This is a custom getElementsByClassName function implemented in pure javascript, that works in IE.
Essentially what this script is doing is probing, one by one, all possible options and picks the best one available. These options are:
Native document.getElementsByClassName function.
document.evaluate function, which allows evaluation of XPath queries.
Traversing the DOM tree.
Of course the first one is the best performance-wise, however the latter should be available everywhere including IE 6.
Usage example, which is also available on the page, looks like this:
getElementsByClassName("col", "div", document.getElementById("container"));
So the function allows 3 parameters: class (required), tag name (optional, searches for all tags if not specified), root element (optional, document if not specified).
Update. The solution linked in the blog post is hosted on the Google Code which is shutting down in Jan 2016. However the author has made it available on GitHub. Kudos to flodin pointing this out in the comments.
Internet Explorer 8 and older does not support getElementsByClassName(). If you only need a solution for IE8, it supports querySelectorAll(), you can use one of these instead. For older IEs you have to provide your own implementation, and for some other ancient browsers that support it you can also use evaluate() which runs XPath expressions.
This code provides a document.getElementsByClassName method if it does not exist yet using the methods I've described:
if (!document.getElementsByClassName) {
document.getElementsByClassName = function(search) {
var d = document, elements, pattern, i, results = [];
if (d.querySelectorAll) { // IE8
return d.querySelectorAll("." + search);
}
if (d.evaluate) { // IE6, IE7
pattern = ".//*[contains(concat(' ', #class, ' '), ' " + search + " ')]";
elements = d.evaluate(pattern, d, null, 0, null);
while ((i = elements.iterateNext())) {
results.push(i);
}
} else {
elements = d.getElementsByTagName("*");
pattern = new RegExp("(^|\\s)" + search + "(\\s|$)");
for (i = 0; i < elements.length; i++) {
if ( pattern.test(elements[i].className) ) {
results.push(elements[i]);
}
}
}
return results;
}
}
If you don't like something about it, you can use your favorite search engine to find a different one.
The method doesn't exist in IE6. If you want to select elements by class and don't want to use a library, you simply have to loop through all elements in the page and check for the class in their className property.
function getElementsByClassName(className) {
var found = [];
var elements = document.getElementsByTagName("*");
for (var i = 0; i < elements.length; i++) {
var names = elements[i].className.split(' ');
for (var j = 0; j < names.length; j++) {
if (names[j] == className) found.push(elements[i]);
}
}
return found;
}
Demo: http://jsfiddle.net/kYdex/1/
If getElementsByClassname does not support is error in some old browsers
Simply try
var modal = document.getElementById('myModal');
modal.onclick= function(){
Then do what ever onclick function or another function by using getElementById
modal.style.display = "none";
}

javascript modify css class property while knowing only the class' name

Here's my css class:
.my-css-class-name
{
display: block;
}
And I have one element at my webpage that uses this class. I want to modify this element's "display" property.
I would happily do this by getting a handle to that element and then modifying what I need, BUT, I don't know the element's name - it's being randomly generated (it's a third-party extension).
So I figured I'm gonna have to get a handle to ".my-css-class-name" and modify that property directly.
How do I get there, cross-browser (major ones) solution?
Edit #1:
I'm looking for compatibility with newer browsers.
Well, theoretically, it's easy.
document.getElementsByClassName("my-css-class-name")[0].style.display = "something";
In case you need IE compatibility:
/*
Developed by Robert Nyman, http://www.robertnyman.com
Code/licensing: http://code.google.com/p/getelementsbyclassname/
*/
var getElementsByClassName = function (className, tag/* "a","div",... */, elm/*parent*/){
if (document.getElementsByClassName) {
getElementsByClassName = function (className, tag, elm) {
elm = elm || document;
var elements = elm.getElementsByClassName(className),
nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
returnElements = [],
current;
for(var i=0, il=elements.length; i<il; i+=1){
current = elements[i];
if(!nodeName || nodeName.test(current.nodeName)) {
returnElements.push(current);
}
}
return returnElements;
};
}
else if (document.evaluate) {
getElementsByClassName = function (className, tag, elm) {
tag = tag || "*";
elm = elm || document;
var classes = className.split(" "),
classesToCheck = "",
xhtmlNamespace = "http://www.w3.org/1999/xhtml",
namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
returnElements = [],
elements,
node;
for(var j=0, jl=classes.length; j<jl; j+=1){
classesToCheck += "[contains(concat(' ', #class, ' '), ' " + classes[j] + " ')]";
}
try {
elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
}
catch (e) {
elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
}
while ((node = elements.iterateNext())) {
returnElements.push(node);
}
return returnElements;
};
}
else {
getElementsByClassName = function (className, tag, elm) {
tag = tag || "*";
elm = elm || document;
var classes = className.split(" "),
classesToCheck = [],
elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
current,
returnElements = [],
match;
for(var k=0, kl=classes.length; k<kl; k+=1){
classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
}
for(var l=0, ll=elements.length; l<ll; l+=1){
current = elements[l];
match = false;
for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
match = classesToCheck[m].test(current.className);
if (!match) {
break;
}
}
if (match) {
returnElements.push(current);
}
}
return returnElements;
};
}
return getElementsByClassName(className, tag, elm);
};
getElementsByClassName("my-css-class-name")[0].style.display = "something";
Following your response in the comment, if the element is being generated by Jquery, then the library is most likely installed. Here is something you can try to select it via Jquery and change the require property.
$(document).ready( function(){
$('.my-class-name').css('display', 'block');
});
Substituting 'block' for whatever setting you require.
If Jquery is included it should do what your require on page load. You can also attach it to other events as well.
$(document).ready(function(){
$('.my-class-name').click(classClicked);
})
function classClicked(){
$(this).css('display','block')
}
getElementByClassName is not possible (in older browsers) but there are work arounds including iterating through every element. See here for discussion Do we have getElementsByClassName in javascript?
Some newer browsers support document.getElementsByClassName right out of the box. Older browsers do not and you have to use a function that loops through the elements of the page.
A flexible getElementsByClassName function with support for browser versions that do not support the native function as thejh suggested may be what you are looking for. It would work, at least. However, for what you are doing, it may be useful to look at the document.styleSheets property. With this route, you can change the CSS rule directly, which, if it worked consistently across browsers, would be the better route here. Unfortunately, browser compatibility in this area is far from consistent, as shown here: http://www.quirksmode.org/dom/w3c_css.html
If you are still interested, have a look at this question: Changing a CSS rule-set from Javascript

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.

Categories

Resources