I'm writing a javascript function where I get a ul object from my HTML and want to set the text of one of the li elements in theul`. I'm doing:
list = document.getElementById('list_name');
Then I want to access the ith li element of list using a loop.
I have:
for (i = 0; i < 5; i++) {
list[i].innerHTML = "<a>text</a>";
}
but this is not working. What is the proper way to do it?
You need to access the child li elements of the ul. JavaScript and the DOM API can't automagically do that for you.
var list = document.getElementById('list_name'),
items = list.childNodes;
for (var i = 0, length = childNodes.length; i < length; i++)
{
if (items[i].nodeType != 1) {
continue;
}
items[i].innerHTML = "<a>text</a>";
}
You could also use getElementsByTagName('li') but it will get all descendent li elements, and it seems you want only the direct descendants.
You could also avoid innerHTML if you want.
var a = document.createElement('a'),
text = document.createTextNode('text');
a.appendChild(text);
items[i].appendChild(a);
innerHTML can cause issues, such as lost event handlers and the performance issue of serialising and re-parsing the HTML structure. This should be negligible in your example, however.
jQuery Sample code, although the others work:
$("#list_name li").text("<a href=''>text</a>");
Its much more succinct with jQuery
You can try the following
var el = document.createElement("li"),
content = document.createTextNode("My sample text"),
myUl = document.getElementById("ulOne");
el.appendChild(content);
el.id = "bar";
myUl.appendChild(el);
Here's the demo: http://jsfiddle.net/x32j00h5/
I prefer a aproach using getElemenetByTagName, if somehow you get a extra node like a script tag or a span you will have problems. A guess this code will help you:
var list = document.getElementById("mylist");
var items = list.getElementsByTagName("li");
for(var i = 0, size = items.length; i< size; i++){
items[i].innerHTML = "<a href='#'>LINK</a>";
}
Related
I'm trying to write a javascript what is searching for all of the links on the page, then it is adding them to the bottom, under the original content.
"Document.links" seems to do the finding part, it is also listing them, but they are not clickable. So I tried to add some html codes (startHref and endHref lines), which broke the whole thing of course.
My (non-working) script:
var links = document.links;
for(var i = 0; i < links.length; i++) {
var preLink = document.createTextNode("LINK: ");
var linkHref = document.createTextNode(links[i].href);
var lineBreak = document.createElement("br");
var startHref = document.createElement("a href="");
var endHref = document.createElement(""");
document.body.appendChild(preLink);
document.body.appendChild(startHref);
document.body.appendChild(linkHref);
document.body.appendChild(endHref);
document.body.appendChild(lineBreak);
}
If this will work I'd also like to have them listed with a number in front of each line (starting with 1 - could be set in the preLink part) - if not too hard to implement.
Also, is there a way to list not all of the links, but only those matching with something? Like only links with a specific domain. Thank you!
As you have already found out, you can get all links in a document with:
var links = document.links;
Now you have an HTMLCollection. You can iterate through it and display all links. For better layout you can put them in a paragraph (p). This would be the loop:
for (var i = 0; i < links.length; i++) {
var p = document.createElement("p");
p.appendChild(links[i]);
document.body.appendChild(p);
}
Now all links are appended at the end of the page, every link is on its own line and they are clickable. Please try this out.
EDIT: as of your comment, if I understand it right, you have just to put one additional line:
for (var i = 0; i < links.length; i++) {
var p = document.createElement("p");
// the following line is added
links[i].innerHTML = links[i].href;
p.appendChild(links[i]);
document.body.appendChild(p);
}
That line will simply replace the inner HTML of the link with its value for the attribute href.
EDIT:
The variable links just points to document.links. The existing links are therefore removed from their original position and appended to the end. If you try to create new links in the for loop, like document.createElement("a") you will create an endless loop, because you're iterating through all links in the document. You remember, the variable links is not a snapshot of document.links when created, but points to it.
You can work around this with creating an array:
var links = [];
// populate the array links
for (var j = 0; j < document.links.length; j++) {
links.push(document.links[j].cloneNode());
}
Now this is a snapshot of all links on the page. Every links is cloned and pushed to the array. Now run the for loop and the original links aren't removed.
If the original link was something like:
This is an example.
it will become:
http://example.com
But if you want just:
http://example.com
then you have to adapt the code:
for (var i = 0; i < links.length; i++) {
var p = document.createElement("p");
var a = document.createElement("a");
a.href = links[i].href;
a.text = links[i].href; // you can use text instead of innerHTML
p.appendChild(a);
document.body.appendChild(p);
}
If you want to style the output you can add classes like this:
p.classList.add("my-css-class");
I hope this helps you to achieve your goal.
i am using a for loop to generate paragraph tags based on the length of my array. I want each of these p tags generated to have the same innerHTML. I can get the tags to generate with the class name but the innerHTML remains blank.
I have tried the following to no avail, not sure what I am doing wrong.
for (i = 0; i < numArray.length; i++) {
var line = document.createElement("p");
line.className = "line";
document.body.appendChild(line);
var b = document.getElementsByClassName("line");
b.innerHTML = "|";
}
You don't need to call getElementsByClassName you can change the innerHTML of line since you already have the reference to the DOM element.
for (i = 0; i < numArray.length; i++) {
var line = document.createElement("p");
line.className = "line";
line.innerHTML = "|";
document.body.appendChild(line);
}
And explaining why it didn't work, it's because getElementsByClassName returns a collecion of elements, you need to loop through them.
getElementsByClassName should return an array of elements, not a single element. You could try: getElementsByClassName('line')[i], if there is some reason you are doing that specifically.
Note: getElementsByClassName('line')[i] may not refer to the object you just created, unless there are no other "line"s on the page. It scans the document for all elements that have a class called line, which could be paragraphs or other element types.
For a better alternative, please refer to changes made below. This:
caches the numArray length into a variable, so you are not performing that operation at each loop iteration
sets the HTML and ClassName of the element you created before attaching it to the document; which has a number of performance benefits
does not unnecessarily do a DOM lookup for elements, which is expensive
uses the var keyword to avoid scoping conflicts for loop variables
JS Fiddle:
for ( var i=0, n=numArray.length; i < n; i++) {
var line = document.createElement("p");
line.className = "line";
line.innerHTML = '|';
document.body.appendChild(line);
}
I'm using DOMParser() to parse a HTML string, and am trying to get all the child nodes with a for loop. However I do not know how to get the child nodes' nodes, and their children, etc...
var str = "<div><p>paragraph<span>span</span></p></div>";
var doc = new DOMParser().parseFromString(str, 'text/html');
var childnodes = doc.body.childNodes;
for (var i = 0; i < childnodes.length; i++) {
console.log(childnodes[i]);
console.log(childnodes[i].childNodes);
console.log(childnodes[i].childNodes[i].childNodes);
}
This works as I'd like, it gives the div, p, text, and span, but how would I make this work with a for loop that gets all the grandchildren? Without jQuery?
Here's a fiddle with the above code.
You should use recursion for this:
function travelChildren(childnodes){
for (var i = 0; i < childnodes.length; i++) { // for each node in childnodes
console.log(childnodes[i]); // console log current node
travelChildren(childnodes[i].childNodes) // and travel its children
}
}
travelChildren(childnodes) // start recursion with the child nodes you want
For those who can use jQuery, you could do it in a while loop.
var $children = $(document.body).children();
while ($children.length) {
console.log($children.attr('class'));
$children = $children.children();
}
Or as #adeneo suggested, you can use contents():
$(document.body).find('*').contents();
Although, jQuery recommends to "Avoid the All Selector," either way it's likely going to be expensive code.
If there are a bunch of H1 and P tags in my document and there is no ID associated with them, how do I target particular P and H1 tags using JavaScript? I have no control over the creation of the page; thus, I'm resorting to using JavaScript to manipulate on the client side.
This sounds like a sad place to be, but if you've no access, you'll want to use something like:
var pTags = document.getElementsByTagName('p');
for (var i = pTags.length; i--;) {
var self = pTags[i];
self.style.display = 'none';
}
This however will hide all of them, so you'll want to filter out the ones you do have. And the same for your H1 tags. Not an ideal solution as you'll likely run into further issues.
You mention that some do not have ID attributes, you could filter those out:
var pTags = document.getElementsByTagName('p');
for (var i = pTags.length; i--;) {
var self = pTags[i];
if (!self.hasAttribute('id')) {
self.style.display = 'none';
}
}
var ps = document.getElementsByTagName('p');
for (var i = 0, l = ps.length; i < l; i++) {
ps[i].setAttribute('style', 'display: none');
}
Repeat for h1 tags.
By Order
By Value
By constellation (So you know there is a img bevor the h1 or something else)
I used $('#ul li').get() to get all the list elements and stored in an array, each of this list elements have classes...
var i;
var listClass = ('#ul li').get();
for(i=0;i<listClass.length;i++){
var theClass = listClass[i].attr("class"); //<--what's the proper function/method/code for this?
var content = listClass[i].innerHTML; //<-- works very well
//other codes here
}
How may i able to get the classes of each list elements...Thanks!
You can use jQuery's own map to do that:
alert($('#ul li').map(function() {
return this.className;
}).get());
http://jsfiddle.net/MhVU7/
for example. You can do anything with the returned array.
The reason the way you're doing it isn't working is because you're calling the non-existent method .attr on a native DOM element - it's not an extended jQuery object.
var lis = document.getElementById("ul").children;
for (var i = 0, len = lis.length; i < len; i++) {
var li = lis[i],
className = li.className,
value = li.value,
text = li.textContent;
// code
}
The get() method returns a native array of DOM elements, not a jQuery object.
You should use jQuery:
var lists = $('ul li');
var className = lists.eq(i).attr('class');
var content = lists.eq(i).text();
If you want to loop through all the elements
$('ul li').each(function(){
var className = $(this).attr('class');
var content = $(this).text();
});
I have commented the code to better help you understand it.
$("#ul li").each(function() { /* you should only be using # selector to identify id's - if it's all ul's you want just put ul. */
var klass = this.className; /* this refers to the native DOM object, which contains className */
var textContents = this.innerText || this.textContent; /* the text of the list, does not include html tags */
var childNodes = this.childNodes; /* the child nodes of the list, each unencased string of text will be converted into a TextNode */
console.log(klass + ' ' + textContents); /* replace console.log with alert if you do not have a console */
console.log(childNodes);
});
here is an example of the above.
Good Luck!