I am trying to parse JSON data into specific iterations of a class name "slide_content"
To get something like this:
slide_content[0]
But JS doesn't provide a getElementByClass() selector.
The API data in question is here:
Converting Straight JS to JQuery
Cheers!
Myles
Newer browsers (IE9 and above) have support for document.getElementsByClassName (which ironically means that it has less support than querySelectorAll, but I digress...), but that probably won't meet your compatibility needs. In this case, you can use something like this to get an Array of nodes with the class.
var nodes = document.getElementsByTagName('*'),
targetClass = 'myclass',
result = [];
for(var i = 0, l = nodes.length; i < l; i++){
if((nodes[i].className + ' ').indexOf(targetClass + ' ') !== -1){
result.push(nodes[i]);
}
}
This is not an exact duplicate of getElementsByClassName, since that function returns a NodeList, but it should be close enough for most purposes.
Use jQuery. It allows you to use $('.someClass') to retrieve all elements with a given class name.
If you cannot use jQuery or another JS library for some reason, simply use the Sizzle selector engine which is also used by jQuery - it's not very much code so you could even copy&paste it into one of your project's JS files (but don't do that, it's ugly :p). But since you tagged your question with jquery I assume you can use jQuery...
Related
I want to take a string that is legal HTML and extract some data from it, based on tags and their attributes. I know that this is possible with jQuery and that it has several built-in methods for this, but I'm trying out Angular and I want to avoid using jQuery unless I really, really need to. Does Angular provide its own set of functions for this?
You can do this with even plain Javascript. Here's a simple example. We could answer much more specifically if you showed us exactly what you're trying to extract from the HTML string. Here's a working snippet example that shows the basic concept:
var htmlStr = '<div><div class="item">Bear</div><div class="item">Wolf</div></div>';
var div = document.createElement("div");
div.innerHTML = htmlStr;
var items = div.querySelectorAll(".item");
for (var i = 0; i < items.length; i++) {
document.write(items[i].innerHTML + "<br>");
}
Angular contains a subset of jQuery called jqLite which is documented here. The .find() in jqLite is limited to only search for tag names so .querySelectorAll() which is built into all modern browsers these days would be much more capable.
I have a couple of questions about the inner workings of JavaScript and how the interpreter handles certain queries
The following JQuery will correctly get all the images that contain the word "flowers" in the src
$("img[src*='flowers']");
Jquery makes this very simple but what the pure javascript version?
We have a very large DOM. I take it if I do $("*[src*='flowers']") this will greatly affect performance (wildcard element). I'm interested in what the Javascript interpreter does differently between $("img[src*='flowers']") and $("*[src*='flowers']")
Well, the clearest way to explain the difference is to show you how you'd write both DOM queries in plain JS:
jQuery's $("img[src*='flowers']"):
var images = document.getElementsByTagName('img');//gets all img tags
var result = [];
for (var i = 0; i < images.length;i++)
{
if (images[i].getAttribute('src').indexOf('flowers') !== -1)
{//if img src attribute contains flowers:
result.push(images[i]);
}
}
So as you can see, you're only searching through all img elements, and checking their src attribute. If the src attribute contains the substring "flowers", the add it to the result array.
Whereas $("[src*='flowers']") equates to:
var all = document.getElementsByTagName('*');//gets complete DOM
var result = [];
for (var i =0; i <all.length; i++)
{
if (all[i].hasAttribute('src') && all[i].getAttribute('src').indexOf('flowers') !== -1)
{//calls 2 methods, for each element in DOM ~= twice the overhead
result.push(all[i]);
}
}
So the total number of nodes will be a lot higher than just the number of img nodes. Add to that the fact that you're calling two methods (hasAttribute and getAttibute) for all img elements (thanks to short-circuit evaluation, all elements that don't have an src attribute, the getAttribute method won't be called) there's just a lot more going on behind the scenes in order for you to get the same result.
note:
I'm not saying that this is exactly how jQuery translates the DOM queries for you, it's a simplified version, but the basic principle stands. The second version (slower version) just deals with a lot more elements than the first. That's why it's a lot slower, too.
When you use *[src..] you will try to find all elements from the page, but when you use $("img[src..]") the search is restricted to img elements, like this: imgs = document.getElementsByTagName("img")
Heres a JSFiddle getting those images using pure javascript.
Edit:
turn console on so you can see the return from console.log
The direct JavaScript methods are document.querySelector or document.querySelectorAll. The problem with those is that they are not supported in all browsers, jQuery (through SizzleJS) provides a browser compatible way of doing these things. SizzleJS delegates to document.querySelectorAll if it is available, and it falls back on other mechanisms when it is not available. So unless you want to write the fall back code yourself, it's probably best to stick with something like SizzleJS, which provides the selector functionality without the overhead of jQuery.
I m a JavaScript pure developer i design my own framework when i tested my selectors module i found a very big issue which is performance
in the selectors module i don't do a very complex selector like jquery i do a simple one
my big cause here when i run my selectors in some cases i have to get all elements on the body of the page and have to loop over them to get a specific kind of elements like TD elements for instance , note >>>> dont tell me use getElementsByTagName('TD') cause in my selectors i can make the developer select more than 1 tagName like
getElementsByTagNames('td,tr')
so in that case i have to get all and then loop over and pic only the needed items
i found that way is very performance eater in the other hand jquery have a hilarious speed to select items doesn't jquery do loops also or what so my main question here
how to do a high performed selectors using JavaScript
:)
thanks
doesn't jquery do loops also or what
jQuery is smart enough to use an existing selector library (sizzle.js).
Sizzle is smart enough to let the browser do the work. document.querySelectorAll does the trick.
edit: actually, sizzle.js used to be inherent part of jquery, but is a separate project now
You can still use getElementsByTagName if you do something like this:
function getElementsByTagNames(elements) {
elements = elements.split(",");
var foundElements = [];
for(var i = 0, len = elements.length; i<len; i++) {
foundElements.push(document.getElementsByTagName(elements[i]));
}
return foundElements;
}
Now if you call getElementsByTagNames("tr,div"), an array containing all tr and div elements will be returned.
Hi I would like to do dom selection and manipulation out of the dom.
The goal is to build my widget out of the dom and to insert it in the dom only once it is ready.
My issue is that getElementById is not supported on a document fragment. I also tried createElement and cloneNode, but it does not work either.
I am trying to do that in plain js. I am used to do this with jQuery which handles it nicely. I tried to find the trick in jQuery source, but no success so far...
Olivier
I have done something similar, but not sure if it will meet your needs.
Create a "holding area" such as a plain <span id="spanReserve"></span> or <td id="cellReserve"></td>. Then you can do something like this in JS function:
var holdingArea = document.getElementById('spanReserve');
holdingArea.innerHTML = widgetHTMLValue;
jQuery will try to use getElementById first, and if that doesn't work, it'll then search all the DOM elements using getAttribute("id") until it finds the one you need.
For instance, if you built the following DOM structure that isn't attached to the document and it was assigned to the javascript var widget:
<div id="widget">
<p><strong id="target">Hello</strong>, world!</p>
</div>
You could then do the following:
var target;
// Flatten all child elements in the div
all_elements = widget.getElementsByTagName("*");
for(i=0; i < all_elements.length; i++){
if(all_widget_elements[i].getAttribute("id") === "target"){
target = all_widget_elements[i];
break;
}
}
target.innerHTML = "Goodbye";
If you need more than just searching by ID, I'd suggest installing Sizzle rather than duplicating the Sizzle functionality. Assuming you have the ability to install another library.
Hope this helps!
EDIT:
what about something simple along these lines:
DocumentFragment.prototype.getElementById = function(id) {
for(n in this.childNodes){
if(id == n.id){
return n;
}
}
return null;
}
Why not just use jQuery or the selection API in whatever other lib youre using? AFAIK all the major libs support selection on fragments.
If you wan tto skip a larger lib like jQ/Prototype/Dojo/etc.. then you could jsut use Sizzle - its the selector engine that powers jQ and Dojo and its offered as a standalone. If thats out of the question as well then i suppose you could dive in to the Sizzle source and see whats going on. All in all though it seems like alot of effort to avoid a few 100k with the added probaility that the code you come up with is going to be slower runtime wise than all the work pulled into Sizzle or another open source library.
http://sizzlejs.com/
Oh also... i think (guessing) jQ's trick is that elements are not out of the DOM. I could be wrong but i think when you do something like:
$('<div></div>');
Its actually in the DOM document its just not part of the body/head nodes. Could be totally wrong about that though, its just a guess.
So you got me curious haha. I took a look at sizzle.. than answer is - its not using DOM methods. It seems using an algorithm that compares the various DOMNode properties mapped to types of selectors - unless im missing something... which is entirely possible :-)
However as noted below in comments it seems Sizzle DOES NOT work on DocumentFragments... So back to square one :-)
Modern browsers ( read: not IE ) have the querySelector method in Element API. You can use that to get and element by id within a DocumentFragment.
jQuery uses sizzle.js
What it does on DocumentFragments is: deeply loop through all the elements in the fragment checking if an element's attribute( in your case 'id' ) is the one you're looking for. To my knowledge, sizzle.js uses querySelector too, if available, to speed things up.
If you're looking for cross browser compatibility, which you probably are, you will need to write your own method, or check for the querySelector method.
It sounds like you are doing to right things. Not sure why it is not working out.
// if it is an existing element
var node = document.getElementById("footer").cloneNode(true);
// or if it is a new element use
// document.createElement("div");
// Here you would do manipulation of the element, setAttribute, add children, etc.
node.childNodes[1].childNodes[1].setAttribute("style", "color:#F00; font-size:128px");
document.documentElement.appendChild(node)
You really have two tools to work with, html() and using the normal jQuery manipulation operators on an XML document and then insert it in the DOM.
To create a widget, you can use html():
$('#target').html('<div><span>arbitrarily complex JS</span><input type="text" /></div>');
I assume that's not what you want. Therefore, look at the additional behaviors of the jQuery selector: when passed a second parameter, it can be its own XML fragment, and manipulation can happen on those documents. eg.
$('<div />').append('<span>').find('span').text('arbitrarily complex JS'). etc.
All the operators like append, appendTo, wrap, etc. can work on fragments like this, and then they can be inserted into the DOM.
A word of caution, though: jQuery uses the browser's native functions to manipulate this (as far as I can tell), so you do get different behaviors on different browsers. Make sure to well formed XML. I've even had it reject improperly formed HTML fragments. Worst case, though, go back and use string concatenation and the html() method.
What's the best way to get an array of all elements in an html document with a specific CSS class using javascript?
No javascript frameworks like jQuery allowed here right now, and I could loop all the elements and check them manually myself. I'm hoping for something a little more elegant.
1) Get all elements in the document (document.getElementsByTagName('*'))
2) Do a regular expression match on the element's className attribute for each element
The below answer is now pushing four years old, so it's worth noting that native browser support for getElementsByClassName() has gotten a lot better. But if you must support older browsers, then...
Use one that's already been written. Most major JS libraries include one in some form or another, but if you aren't using one of them then i can recommend Robert Nyman's excellent implementation:
http://code.google.com/p/getelementsbyclassname/
http://www.robertnyman.com/2008/05/27/the-ultimate-getelementsbyclassname-anno-2008/
There are just too many ways to make this (conceptually-simple) routine slow and buggy to justify writing your own implementation at this point.
You can include a getElementsByClass function, or you can use a jQuery selector.
UPDATE: The implementation mentioned by #Shog9 is probably better than that above.
Just to do some follow up, I based my code on the the Robert Nyman implementation posted by Shog9, but departed a little from his exact version, for three reasons:
He allowed you to select a root element and tag type to filter your results. I don't need that functionality and so by removing it I was able to simplify the code significantly.
The first thing his code does is see if the function in question already exists, and if it does he provides his own implementation anyway. That just seemed... odd. I understand he was adding functionality to the original, but again: I'm not using those features.
I wanted an additional bit of syntactic sugar- to be able to call it like I would call document.getElementById() or document.getElementsByTagName().
Note that I still relied mostly on his code. His javascript skills are obviously far beyond my own. I did try to factor out some redundant variables, but that's about it.
With that in mind, here is what I ended up with (seems to work in IE6, IE7, Firefox 3, and Chrome see new note at the end):
if (!document.getElementsByClassName)
document.getElementsByClassName = function (className)
{
var classes = className.split(" ");
var classesToCheck = "";
var returnElements = [];
var match, node, elements;
if (document.evaluate)
{
var xhtmlNamespace = "http://www.w3.org/1999/xhtml";
var namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace:null;
for(var j=0, jl=classes.length; j<jl;j+=1)
classesToCheck += "[contains(concat(' ', #class, ' '), ' " + classes[j] + " ')]";
try
{
elements = document.evaluate(".//*" + classesToCheck, document, namespaceResolver, 0, null);
}
catch(e)
{
elements = document.evaluate(".//*" + classesToCheck, document, null, 0, null);
}
while ((match = elements.iterateNext()))
returnElements.push(match);
}
else
{
classesToCheck = [];
elements = (document.all) ? document.all : document.getElementsByTagName("*");
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)
{
node = elements[l];
match = false;
for (var m=0, ml=classesToCheck.length; m<ml; m+=1)
{
match = classesToCheck[m].test(node.className);
if (!match) break;
}
if (match) returnElements.push(node);
}
}
return returnElements;
}
Update:
One new note on this. I've since re-read the notes on the original implementation, and I understand now that my code could fall down in the case where the existing browser has it's own implementation, because the default implementations return a nodelist where this returns an array. This includes the more recent firefox and safari, and opera browsers. Most of the time that won't matter, but in some situations it could. That explains item #2 from list above.
What that means is that while my code technically does work everywhere, it could result in subtly different (read: hard to debug) behavior in different places, and that's not good. I should fix this to either also return a nodelist or override the supplied method to return an array (which is what the original did). Probably the former would be simpler, but that latter would be better.
However, it's working at the moment in the local intranet environment (pretty much all IE), so for the time being I'll leave the fix as an exercise for the reader.
If using a framework, they all have selections using CSS Selectors.
Otherwise.
var getElementsByClassName = function(cls, sc){
//Init
var elements, i, results = [], curClass;
//Default scope is document
sc = sc || document;
//Get all children of the scope node
elements = sc.getElementsByTagName('*');
for( i=0; i < elements.length; i++ ){
curClass = elements[i].getAttribute('class');
if(curClass != null){
curClass = curClass.split(" ");
for( j=0; j < curClass.length; j++){
if(curClass[j] === cls){
results.push( elements[i] );
break;
}
}
}
}
return results;
};
Just wrote it right now, just for you. :) Feel free to use.
Use jquery, it can't be more convenient.
$(".theclass")
or
$(".theclass"),makeArray() if you want a native JS array
Keep in mind that atleast FF3 already has a native implementation of getElementsByClassName afaik.
If you're going to implement your own solution, maybe you should try to find a xpath-solution since all modern browser have native support for xpath.
#shog9, #user28742, #bdukes -
I'm doing some custom development in SharePoint for a modular thing (custom field definition) I hope can be re-used across many sites.
Since I can't know ahead of time if any given SharePoint site will have jQuery or any other library available to it --- I still need to write things in raw javascript so I can have a degree of confidence that the functionality I'm trying to achieve will stand on it's own.
Thanks Dmitri for your particular implementation. Short enough for my purposes.
In other recent efforts, I had to modify a e-commerce store (of my client's choosing) and some of my attempts to get jQuery rigged into it actually conflicted with whatever custom libraries they had previously rigged. I could have been persistent, and banged out a way to implement jQuery into their proprietary system.. or.. even more quickly.. just write some good ol' fashioned javascript.
Libaries ARE NOT ALWAYS THE BEST ANSWER!!!!!!!!!!!!!!!!
(and I love jQuery more than my grandmother)
There is no such thing as a CSS class. CSS has rule-sets and selectors (including the class selector).
Do you mean an HTML class? The usual way is to loop over every element in the document (using document.getElementsByTagName('*') (for efficiency, use a specific tag name if you know the class will only be applied to elements of a certain type) and test the className property of each (noting that the property contains a space separated list of class names, not a single class name).
A number of libraries (such as jQuery or YUI) have functions to simply this.
Do you mean a CSS selector? This gets more complex, and turning to a library is almost certainly the right thing to do here. Again, jQuery or YUI are decent choices.
If you want to do something for all the element with same id in a document.
Although simple but sometime mind dont give green signals
var x = document.getElementById(elementid);
while(x){
document.removechild(x);
x = document.getElementById(elementid);
}