how browser find collection elements when we are using css selector - javascript

I want to know how browsers find html collection elements when we use css selector.for example.
<div>
<p class="color">I'm p1</p>
</div>
<div>
<div>
<p class="color">I'm p2</p>
</div>
</div>
<p class="color">I'm p3</p>
when we use $("p") or $(".color") we will get three p elements.
so,my question is the order of finding those elements.
(p1,p2,p3) or (p3,p1,p2) or others
because html is a dom tree,the browser may use tree traversal algorithms,which have 5 kinds of(depth-first,pre,in,post,breadth).So,which algorithm is the browser taken.

In that specific use case you will get:
I'm p1
I'm p2
I'm p3
even without to use jQuery.
var p = $(".color");
for(var i=0; i<p.length; i++) {
var el = p.eq(i);
console.log(el.text());
}
console.log("test");
var p2 = document.querySelectorAll(".color");
for(var i=0; i<p2.length; i++) {
var el = p2[i];
console.log(el.innerHTML);
}
JSFiddle -> http://jsfiddle.net/RSEyf/3/
So, it looks like the browser gets the elements in their order in the html.
It is the same even if you use just p instead of .color.

Related

Select nested elements by name attribute javascript(no jquery)

So I have this HTML code and I need to select the elements by their name attribute. The problem is I have multiple elements with the same structure and I need to go throw them with a loop.
<div class="res">
<h4 name="title">title</h4>
<span name="span1"></span>
<span name="span2"></span>
<p name="p1"></p>
<p name="p2"></p>
</div>
I need to select each one of the elements inside the .res div element by their name(or if there's a better solution I'd like to you).
document.getElementsByName("res");
document.getElementsByName("title");
document.getElementsByName("span");
or you can loop through the elements if you don't want to hard-code the name.
You could use .querySelector() like :
document.querySelector('[name="xxxxxx"]');
If you want to loop through all the res containers you could use .querySelctorAll() like :
var containers = document.querySelectorAll('.res');
for( var i = 0; i < containers.length; i++) {
console.log( containers[i].querySelector('[name="title"]').textContent );
}
You can use the DOM Element.children attribute in pure javascript
var children = res.children;
for (var i = 0; i < children.length; i++) {
var child = children[i];
// Do stuff
}
You can use querySelectorAll and inside loop handle every element.
const elements = document.querySelectorAll(".res > *");
elements.forEach(element => {
console.log(element);
});
<div class="res">
<h4 name="title">title</h4>
<span name="span1"></span>
<span name="span2"></span>
<p name="p1"></p>
<p name="p2"></p>
</div>

Get all tag nodes inside another tag recursively

I have an html document consists of a <div id = "main">. Inside this div may be several levels of nodes, without a precise structure because is the user who creates the document content.
I wanto use a JavaScript function that returns all nodes within div id = "main". Any tag is, taking into account that there may be different levels of children.
For now I have this function that returns all tags, even those outside to div id = "main":
function getNodes() {
var all = document.getElementsByTagName("*");
for (var elem = 0; elem < all.length; elem++) {
//do something..
}
}
As such this document:
<div id="main">
<h1>bla bla</h1>
<p>
<b>text text text </b> text text <i>text</i>.
<img src=".."></img>
</p>
<div>
<p></p>
<p></p>
</div>
<p>..</p>
</div>
The function getNodes would return an array of object nodes (I don't know how to represent it, so I list them):
[h1, p, b, i, img, div, p, p, p]
Thank you
Use document.querySelectorAll. It returns a NodeList, not an array, but you can loop over it in the same way:
function getNodes() {
var all = document.querySelectorAll("#main *");
for (var elem = 0; elem < all.length; elem++) {
//do something..
}
}
http://jsfiddle.net/suuja4L5/
Just get the parent element and then get the descendents just as you did:
var mainDiv = document.getElementById("main");
mainDiv.getElementsByTagName("*")
if you want all child of <div id="main">,then use the following :
var children = document.querySelector("#main").children;

JavaScript - innerHTML to change more then first occurrence plus random array

I have two baffling things going on,
First: Is I’m trying to use the .innerHTML to change more than just the first occurrence.
Second: Is that I’m trying to have a random word replace the .innerHTML.
I've only been able to change the first word let alone all plus the random is a complete fail, any help would be appreciated.
Hello <p id="p1">World!</p>
Hello <p id="p1">World!</p>
Hello <p id="p1">World!</p>
<script type="text/javascript">
document.getElementById("p1").innerHTML="newWorld()";
function newWorld() {
var worlds = new Array ("Pluto!", "Mars!", "Saturn!", "Earth!", "Mercury!");
var whichWorld = Math.floor(Math.random()*worlds.length);
worlds[whichWorld]();
};
</script>
IDs in HTML documents are meant to be unique. The function getElementById will only ever return 1 element, nothing more. For groups of similar elements, you want to give them all a common class and then use getElementsByClassName (notice the plural Elements vs Element) - this function won't work with IE 8 or earlier, however, so if you need to support IE you would have to do getElementsByTagName and then filter in only those that have the class you want.
As far as the second part of the code, first you are setting the innerHTML to the actual string newWorld() not to the return value of the function (which there is none, as you are not currently returning something from within newWorld) - I think you meant to do document.getElementById("p1").innerHTML = newWorld();. Secondly, the random part of the code is correct and should be choosing a random planet each time. The end of the code is a bit puzzling, however - what exactly are you trying to do there? worlds[whichWorld] is going to be a string (Earth!, etc.) not a callable function. If worlds was an array of functions then the code would work (assuming you also returned it, since you intend to set it as the innerHTML)
In short, something like this would be the "proper" way to set all <span> elements within a parent element to a random planet:
<div id="planets">
<p>Hello <span>World!</span></p>
<p>Hello <span>World!</span></p>
<p>Hello <span>World!</span></p>
</div>
And the Javascript:
var spans = document.getElementById('planets').getElementsByTagName('span');
for(var i = 0; i < spans.length; i++) {
spans[i].innerHTML = randomWorld();
}
function randomWorld() {
var worlds = ["Pluto!", "Mars!", "Saturn!", "Earth!", "Mercury!"];
var whichWorld = Math.floor(Math.random() * worlds.length);
return worlds[whichWorld];
}
And here it is in action. You are clearly new to Javascript so I encourage you to continue to try and learn the basics of it. Eventually, however, you will want to look into libraries such as jQuery which make a lot of the tediousness of writing cross-browser Javascript go away.
According to HTML standard id must be unique, thus getElementById always return 1 element (usually the first found in the HTML.
You could write:
Hello <p class="planet">World!</p>
Hello <p class="planet">World!</p>
Hello <p class="planet">World!</p>
<script type="text/javascript">
var planets = document.getElementsByClassName("planet")
for (var i=0; i < planets.length; i++) {
planets[i].innerHTML = newWorld();
}
function newWorld() {
var worlds = new Array ("Pluto!", "Mars!", "Saturn!", "Earth!", "Mercury!");
var whichWorld = Math.floor(Math.random()*worlds.length);
return worlds[whichWorld];
}
</script>
I know jQuery is out of the scope of the question, but with a library such as jQuery (and NOT using identical ids) it would be possible to change the content of several element with one statement...
Ids in HTML are supposed to be unique. As such, the getElementById method only returns the first element with the given ID. You've got all the logic right, but you can simplify your answer a bit. Change the ids to classes and use the getElementsByClassName method like so:
Hello <span class="p1">World!</span>
Hello <span class="p1">World!</span>
Hello <span class="p1">World!</span>
<script type="text/javascript">
var worlds = ["Pluto!", "Mars!", "Saturn!", "Earth!", "Mercury!"];
var pTags = document.getElementsByClassName("p1");
for (i = 0; i < pTags.length; i++)
{
pTags[i].innerHTML = worlds[Math.floor(Math.random() * worlds.length)];
}
​</script>
DEMO
Note that the getElementsByClassName method doesn't work in IE8 or earlier. So if you want it to be backwards compatible with those browsers, you'll either need to use the getElementsByTagName and filter them manually or use jQuery.
JAVASCRIPT DEMO, WORKS ON ALL BROWSERS
JQUERY DEMO
Use a function that gives you a group of elements such as querySelectorAll or getElementsByTagName or getElementsByClassName:
Hello <p class="world">World!</p>
Hello <p class="world">World!</p>
Hello <p class="world">World!</p>
<script type="text/javascript">
var newWorld = function () {
var worlds = new Array ("Pluto!", "Mars!", "Saturn!", "Earth!", "Mercury!");
var whichWorld = Math.floor(Math.random()*worlds.length);
return worlds[whichWorld];
};
var worlds = document.getElementsByClassName("world");
for (var i=0; i < worlds.length; i++) {
worlds[i].innerHMTL = newWorld();
}
</script>
To mark multiple elements, you should use class attribute.
Multiple elements in DOM can have same value of class attribute,
but the value of id attribute should be unique.
So the example may look like:
<button id="change-world-btn">Change World</button>
<hr />
<h4>Elements with target class name:</h4>
Hello <span class="world-name">World!</span><br />
Hello <span class="world-name">World!</span><br />
Hello <span class="world-name">World!</span><br />
<hr />
<h4>Element with different class name:</h4>
Hello <span class="other-class">World!</span><br />
<script type="text/javascript">
var worlds = new Array ("Pluto!", "Mars!", "Saturn!", "Earth!", "Mercury!");
function newWorld() {
return worlds[Math.floor(Math.random() * worlds.length)];
}
elements = document.getElementsByTagName('span');
document.getElementById('change-world-btn').onclick = function() {
world = newWorld();
for(var i = 0, el; el = elements[i++];) {
if(el.className == 'world-name') {
el.innerHTML = world;
}
}
};
​</script>
Try it.
Also you can use document.getElementsByClassName function to simplify the task, but this function is not supported in IE < 9.

javascript selectors

How does one select DOM elements in javascript?
Like for example:
<div class="des">
<h1>Test</h1>
<div class="desleft">
<p>Lorem Ipsum.</p>
</div>
<div class="Right">
<button>Test</button>
</div>
</div>
Now how do i select h1? This is just a part of a bigger Page, so cannot use getElementsByTagName(), since others might get selected. Also since there might be other h1's in the document later, i cannot attach the index(body's) to above.
Is there a simple way to select, say <h1> tag which is under the classname of desleft?
I cannot use jQuery or any other libraries.
You can use this to get to your H1:
var des = document.getElementsByClassName('des')
var fc = des[0].getElementsByTagName('h1')
alert(fc[0].innerHTML)
w3.org has selectors now (http://www.w3.org/TR/selectors-api/#examples). Here are 2 different ways that worked for me on Chrome. You may want to use querySelectorAll function that returns a list.
<script type="text/javascript">
//looks for <h1> tag under <div> with className "des"
showOff1 = function() {
var x = document.querySelector(".des h1");
alert(x.innerHTML);
}
//looks for <div> tag with className "desleft" and then use previousSibling to traceback <h1> tag
showOff2 = function() {
var y = document.querySelector("div.desleft");
var z = y.previousSibling.previousSibling;
alert(z.innerHTML);
}
</script>
<body onload="showOff2();">
Use querySelectorAll
You can use querySelectorAll:
// Will return a NodeList even if there is only one element found
var heading = document.querySelectorAll('.des > h1');
heading[1].style.color = 'red'; // NodeList is similar to an array
This will return a NodeList.
or
Use querySelector to return the first element found:
var first_heading = document.querySelector('.des > h1');
first_heading.style.color = 'blue';
Commonly used with an id selector #single-header-id.
Here's a demo
getElementsByTag()
Would be a function that you can start with, and then you can filter for the DOMElements that have the class.
var h1_array = document.getElementsByTag('h1');
var h1_class_array = [];
for (var i=0, len=h1_array.length; i < len; i++) {
if (h1_array[i].className.indexOf('classname') !== -1) {
h1_class_array.push(h1_array[i]);
}
}
The .indexOf function returns -1 if the needle is not found in the haystack.
Now re-reading your question, why not just give your h1's id's ?
DOM traversal is one of javascript's glaring issues (enter jQuery).
a simple getElementById() would save you a headache, and ids on all your h1's would be much cleaner in the end than trying to formulate an algorithm to select them by other means.
If you mean to select a h1 that is before the first element of class desleft, you could always do this:
document.getElementsByClassName("desleft")[0].previousSibling.previousSibling
Example: http://jsfiddle.net/Xeon06/ZMJJk/
previousSibling needs to be called twice because of the empty text node between the two. That's why using libraries to do this stuff is really the best way to go.
var h1 = document.querySelector('.desleft').previousElementSibling;
Find element with className='desleft' using selector '.desleft'
Just move back to previous element (not to previous node!)

Javascript DOM howto?

I am a javascript noob.
I would like to select the second 'p' element of the div.box.
How do I do this?
Thanks a lot!
Tom
To get second p element of div with class box you'd do this:
var paragraph = null;
var divs = document.findElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
var div = divs[i];
if (div.class == 'box') {
var paragraphs = div.getElementsByTagName('p');
if (paragraphs.length > 1)
paragraph = paragraphs[1];
break;
}
}
The paragraph would then be in the paragraph variable (or null if it wasn't found).
However you can do this much easier with a library such as jQuery:
var paragraph = $('div.box p:eq(1)');
Without using jQuery, the basic method would be to attach an unique ID to your Dom element
<p id="second_p_elmt"> [...] </p>
and then accessing it through the getElementById() method:
<script ...>
var second_p_elmt = document.getElementById('second_p_elmt');
</script>
<script type="text/javascript">
var boxElem = document.getElementById('box'),
pElems = boxElem.getElementsByTagName('p'),
whatYouWant = pElems[1]; // [1] is the second element in the response from getElementsByTagName
</script>
You have several options. As stated above, you could use one of the excellent frameworks, like jQuery or prototype. Or you give the <p/> an ID, that you can use simply with document.getElementById().
Then, as reko_t pointed out, without the above, you must write a lengthy DOM traversing code (which is preferable, if you don't use JS frameworks elsewhere, over embedding them only for this task).
In the most recent browsers (namely, IE>=8, FF>=3.5, recent Opera and Safari > 3) you can also use this simple snippet:
var p = document.querySelectorAll("div.box p");

Categories

Resources