I have written a lot of JavaScript code using getElementsByClass name and now realised this is not supported in IE8 so am trying to swap them all for the jQuery equivalent.
My code runs without errors using
div1.getElementsByClassName("div2");
however if I swap this line for
$(".div1 .div2");
my code produces an error "Uncaught NotFoundError: An attempt was made to reference a Node in a context where it does not exist."
What is the difference between the JavaScript code and jQuery code that could make the code behave differently?
If you've already written code using getElementsByClassName, you might be better off using a shim or polyfill so you don't have to rewrite existing code.
Unfortunately, most of the stuff out there only supplies document.getElementsByClassName, so if you're using it from other elements, you'll have to roll your own you can try this one I wrote a while back.
// getElementsByClassName polyfill
(function(){
if (document.getElementsByClassName)
return;
if (!window.Element)
throw "Can't polyfill getElementsByClassName";
function gEBCN(className) {
var all = this.getElementsByTagName("*"),
rex = new RegExp("(?:\\s|^)" + className + "(?:\\s|$)"),
out = [],
element, i;
for (i = all.length; i--;) {
element = all[i];
if (element.className.match(rex))
out.unshift(element);
}
return out;
}
var el = window.Element.prototype;
var doc = document.constructor.prototype;
el.getElementsByClassName = doc.getElementsByClassName = gEBCN;
}());
This script checks if document.getElementsByClassName exists, and if it doesn't, it creates document.getElementsByClassName and Element.prototype.getElementsByClassName with equivalent functionality. Since all HTML elements have Element.prototype in their prototype chain, you'll be able to call .getElementsByClassName on any element, just as you can in any browser that has native support for the function. In other words, you can just drop this code at the top of your file or put it a separate file and include it, and then your current scripts should work in old IE and any other browsers that don't support .getElementsByClassName.
Note that jQuery 2.x does not support IE6/7/8. This might be the problem. Instead, use the 1.x branch (for example version [1.10.2]), which still supports those browsers.
When using a 1.x version of jQuery, the following should be the correct selector for what you want.
$(".div1 .div2") //or:
$(".div1").find(".div2") // or, if .div2 is a direct descendant:
$(".div1 > .div2")
Related
I am doing some experimentation with GSAP library and i found one pen by Jonathan
http://codepen.io/jonathan/pen/qxsfc
which is pretty much i needed. i forked that pen and made my own and now i am trying to convert the same in vanilla js but the first step it self is not working.
i have converted the anonymous function to a named one and called on window.onload and its working. but now i have to replace all the $ calls of jquery selector to native selectors and its not working
the moment i change
var animContainer = $('.animContainer'),
to var animContainer = document.querySelector('.animContainer'),
my pen is
`http://codepen.io/osricmacon/pen/HAnrt`
any more suggestion on how to go about converting jquery to vanilla js
querySelector stops at the first element it finds, and returns a reference to that one element (or null if it doesn't find it). A closer analogue to jQuery's $() is querySelectorAll, which looks for all matching elements and returns a NodeList (which will be empty if none were found).
Separately from that, the key thing about jQuery is that it's set-based, whereas the DOM API is not. That's probably going to be the biggest thing for you to deal with when converting the one to the other.
For example, in jQuery, this sets the HTML of all div elements to "hey":
$("div").html("hey");
The equivalent using the DOM API might look like this:
var list = document.querySelectorAll("div"); // Or .getElementsByTagName
var i;
for (i = 0; i < list.length; ++i) {
list[i].innerHTML = "hey";
}
A common approach to making that less verbose is to reuse Array's forEach function (which is ES5, but can be shimmed for older browsers), like this:
// You'd probably do this once and reuse it
var forEach = Array.prototype.forEach;
// Where you want to use it:
forEach.call(document.querySelectorAll("div"), function(div) {
div.innerHTML = "hey";
});
Or, of course, to have a toolbelt of utility functions that do that under the covers. Which is, of course, exactly what jQuery is.
Finally, in many cases jQuery reuses the same functions as both setters and getters. The html function, for instance, sets the HTML of the elements in the jQuery set when you give it an argument, but gets the HTML of the first element of the set if you don't:
$("div").html("hey"); // Sets the HTML of all divs
console.log($("div").html()); // Gets the HTML of the *first* div
Note the assymetry: Setting applies to all elements in the set, but getting applies only to the first element in the set (ignoring any others). This is true of all of the functions that do dual duty (html, css, val, attr, prop, ...).
I'm working on an existing web page that has all sorts of javascript that I'm not able to edit. I only have access to a certain part of the page to do my stuff. Now the problem is using jQuery. The previous developer had modified the getElementsByClassName method with a custom version, which I'm assuming is kind of polyfill for IE. But this breaks jQuery that uses getElementsByClassName on supported browsers.
Now how may I revert getElementsByClassName to its original version before my code is executed. I can't find the original method anywhere online. Not using jQuery is not really an option as I'm trying to integrate a big piece of code written with jQuery.
Thanks.
Since the prototype chain of document wasn't altered, you could restore it by deleting the current implementation, as mentioned in the comments:
delete document.getElementsByClassName;
Demo
That will make the implementation available again via the prototype chain.
Old answer
You could try to restore it with this hack:
document.getElementsByClassName = document.documentElement.getElementsByClassName
.bind(document.documentElement);
I'm not certain whether it has any downsides, though.
If you need an implementation of the getElementsByClassName(), you may write something like this:
document.getElementsByClassName=function (theclass) {
els=document.getElementsByTagName("*")
temp=[]
for (var k=0; k<els.length; k++) {
if(els[k].className==theclass){
temp.push(els[k])
}
}
return temp;
}
And there is a good discussion here that you may refer to: http://www.webdeveloper.com/forum/showthread.php?256068-Need-object-getElementsByClassName-snippet
EDIT, taking Jack's first comment on this answer into account, as well as the edited answer by him:
Deleting getElementsByClassName from the prototype chain and thus automatically reverting back to the original function apparently works in itself, but that does leave IE8, which does not support getElementsByClassName.
This script comes very close to the original function, takes multiple classes into account, now deals with hyphens correctly, and makes IE8 support it as well:
document.getElementsByClassName = function(theClass) {
var elemArray = [];
var elems = this.getElementsByTagName('*');
for (var i=0; i<elems.length; i++) {
var allClasses = elems[i].className;
var classRegex = new RegExp('^('+theClass+')$|(\\s'+theClass+'\\b)');
// pattern demo and explanation on http://regex101.com/r/pP8nS2
if (classRegex.test(allClasses) == true)
elemArray.push(elems[i]);
}
return elemArray;
}
Live whole-page demo on http://codepen.io/anon/pen/Hhswl?editors=100, regex pattern demo and explanation on http://regex101.com/r/pP8nS2.
The only limitation I know is that you cannot use this script in the concatenated form of document.getElementById(id).getElementsByClassName(class). You should use document.getElementById(id).querySelectorAll(.class) for that, which is also supported by IE8 (not 7). Mind the dot.
I have a javascript function MyFunc() that does what it has to do with id="item_for_MyFunc".
In the function there is a
var elem = document.getElementById("item_for_MyFunc");
and html body has:
<body onload="MyFunc()">
<p id="item_for_MyFunc">
Everything works, but I want to use this function for several items on the page. That's why I should use <p class="item_for_MyFunc"> several times on the page to be processed by this function, so using id is not a solution.
What changes in the function should be done so it could be changed for class="item_for_MyFunc"?
So what you're doing there is pretty simple. Let me give you a slightly more robust version:
document.addEventListener('load', function(){
var elements = document.querySelectorAll('.myClassName');
for(var i=0, len=elements.length; i<len; i++){
MyFunc.call( elements[i] );
}
}, false);
So old versions of IE, 6 and 7 to be specific, don't have querySelectorAll. I'm assuming you aren't worried about them. If you are, there's other ways to do this and I can show you how if you need.
Basically we're giving all of your elements a class of 'myClassName', and querySelectorAll finds all of them and returns an array of DOM elements.
We then iterate through the list, and execute MyFunc on each of those elements.
Edit
So one key principal of writing good javascript is to separate the js code from your html markup as much as possible. You should almost never use inline event handlers like onload="myFunc" anymore. Use event handlers written in the js itself.
If you have the option, you should use the jQuery library. It makes a lot of this stuff incredibly easy, has great support for very old browsers, and is used on hundreds of thousands of websites.
document.getElementsByClassName
would return an array of all HTML elements using the class name. Iterate over the results and you are set. Supported in all browsers except IE <= 8, FF < 3. Works just like document.querySelectorAll (works in IE >= 7, FF >=3.5)
Refer:
http://quirksmode.org/dom/w3c_core.html#gettingelements
for compatibility chart.
You could try:
var elems = document.getElementsByClassName('myClass');
I've not used that one before, but you could use jQuery as that's even simpler;
var elems = $('.myClass');
I have a problem with old website. All JavaScript code on it use getElemenById function. But tags of site markup doen't have id property, instead they have only name property. Although it still works for IE, browser returns elements even by name property. For all other browsers it's a mistake in JS.
I wonder if there any way to overload this function in other browser to make web site compatible to other browsers?
There's no way to "overload" a function in JavaScript in the sense that you would do so in a strongly-typed language like Java or C. In fact, every function in JavaScript is already overloaded in this sense in that you can call any function with any number and type of arguments.
What you can do, however, is insert your own proxy in front of the existing version, and implement the proxy with whatever behavior you prefer. For instance:
document._oldGetElementById = document.getElementById;
document.getElementById = function(elemIdOrName) {
var result = document._oldGetElementById(elemIdOrName);
if (! result) {
var elems = document.getElementsByName(elemIdOrName);
if (elems && elems.length > 0) {
result = elems[0];
}
}
return result;
};
I wouldn't count on overriding getElementById working properly. Sounds easy enough to do a search and replace that does something like this:
// Replace
document.getElementById("foo");
// With
myGetElementById("foo", document);
// Replace
myElement.getElementById("foo");
// With
myGetElementById("foo", myElement);
Then you can myGetElementById as you want, without worrying about what might happen in old IEs and what not if you override getElementById.
Try getElementsByName. This is used to get a collection of elements with respect to their name
<p id ="myP">
Render this text using the myC class </p>
---------------------------
.teststyle {
background-color:#00ff00;
font-size: 200%;
}
---------------------
window.onload = load;
function load(){
document.getElementById("myP").className = "teststyle";
}
----------------------
Playing with jsfiddle.net and JavaScript I found out that getElementByClass is not supported in JS. I'm wondering why? What if I had a class in my XTHML-code, how can I transform this code?
The other peculiar thing I noticed is: if I use onload = "load()" in the xhtml won't work like if I had "windows.load" in the js-code; why is that? It should be the same, maybe it's just me.
No it doesn't, because the function's name is:
getElementsByClassName
// ^ ^^^^
Note that it is not support in IE before IE9.
Have a look at the documentation of getElementsByClassName.
Regarding the onload issue: Without more code it is hard to tell what you did wrong. If you do
<body onload="load()">
it will work. But doing so (attaching event handlers in the HTML) should be avoided anyway.
I found out that "getElementByClass" is not supported in JS, uhn? funny wondering why?
Because JS has no native DOM manipulation in it. That's a separate API (provided by browsers, some other JS environments, and libraries for those other environments).
… but you probably count browser DOM implementations as part of JS for the purpose of this question so:
Because class isn't a generic DOM concept, it is HTML specific (or at least started out that way). getElementsByClassName (note Name!) is new in draft specifications and not all browsers have implemented it.
so what if I had a class in my XTHML-code how can I transform this code?
You don't use getElementsByClassName in that code, so it doesn't really make much sense.
There are plenty of third party libraries that provide means to get elements based on the classes to which they belong. Some have implementations of getElementsByClassName, some just implement selector engines (such as YUI and jQuery).
The other peculiar thing I noticed is: if I use onload = "load()" in the xhtml won't work like if I had "windows.load" in the js-code...how is dat? it should be the same, maybe it's just me..thanks!
One will overwrite the other.
function getElementsByClassName( strClassName, obj ) {
var ar = arguments[2] || new Array();
var re = new RegExp("\\b" + strClassName + "\\b", "g");
if ( re.test(obj.className) ) {
ar.push( obj );
}
for ( var i = 0; i < obj.childNodes.length; i++ )
getElementsByClassName( strClassName, obj.childNodes[i], ar );
return ar;
}
Usage :
var aryClassElements = getElementsByClassName( 'findMe', document.body );
From : http://www.tek-tips.com/viewthread.cfm?qid=1143850&page=1
Do you guys search on google before posting here ?