I have a jQuery plugin that I want to convert into pure javascript, so that I can drop the dependency on jQuery. The part of the plugin i'm stuck on is this bit, which returns the DOM elements sorted by depth (eg. body's children, then grandchildren, then great-grand-children, etc etc)
var first = $('body'),
output = [];
while(first.length != 0) {
output = $.merge(output, first);
first = first.children();
}
basically I just need the pure javascript version of $('body') , $.merge and children() to help me on my way.
Any help would be much appreciated
Ok, I figured it out myself, it was pretty simple in the end.
// Every Element in the DOM.
var allElements = document.getElementsByTagName('*'),
// All the Element's children sorted by depth,
// ie. body, then body's children, grandchildren,
// so on and so forth.
sortedByDepth = [];
// for every element
for(var i = 0; i<allElements.length; ++i) {
// grab Its children
var allChildren = allElements[i].children;
// for every grabbed child
for(var j = 0; j<allChildren.length; ++j){
// Add it to the sortedByDepth array
sortedByDepth = sortedByDepth.concat(allChildren[j]);
}
}
console.log(sortedByDepth);
Related
I am trying to loop through and increment the following:
var result_types = document.querySelectorAll('[data-title]')[0].attributes[2].nodeValue
specifically to grab and increment this value:
[0].attributes
Currently, I have the following:
var card = document.querySelectorAll('[data-title]')[0].attributes[2].nodeValue;
for (var i = 0; i < card.length; i++) {
console.log(card[i]);
}
I am trying to get this [0].attributes to increment to [1].attributes etc. when it is clicked
I am not sure what you are asking here, but if the issue is looping through the elements, this is happening because you get a NodeList back from querySelectorAll and not an array. Below will let you loop through node elements.
const nodes = document.querySelectorAll('.nodes');
[].forEach.call(nodes, (singleNode) => {
//Whatever you want.
})
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.
var text='<div id="main"><div class="replace">< **My Text** ></div><div>Test</div></div>'
I want to replace div with class="replace" and html entities < > comes inside that div with some other text.
I.e the output :
'<div id="main"> Hello **My Text** Hello <div>Test</div> </div>'
I've tried
var div = new RegExp('<[//]{0,1}(div|DIV)[^><]*>', 'g');
text = text.replace(div, "Hello");
but this will replace all div.
Any help gratefully received!
If a Jquery solution is acceptable:
text = $(text) // Convert HTML string to Jquery object
.wrap("<div />") // Wrap in a container element to make...
.parent() // the whole element searchable
.find("div.replace") // Find <div class="replace" />
.each(function() // Iterate over each div.replace
{
$(this)
.replaceWith($(this).html() // Replace div with content
.replace("<", "<sometext>")
.replace(">", "</sometext>")); // Replace text
})
.end().html(); // return html of $(text)
This sets text to:
<div id="main"><sometext> My Text </sometext><div>Test</div></div>
And to replace it back again:
text = text.replace('<sometext>', '<div class="replace"><')
.replace('</sometext>', '></div>');
http://api.jquery.com/jquery/#jQuery2
http://api.jquery.com/each/
http://api.jquery.com/find/
http://api.jquery.com/html/
In pure JS it will be something like this:
var elements = document.getElementsByClassName('replace');
var replaceTag = document.createElement('replacetext');
for (var i = elements.length - 1; i >= 0; i--) {
var e = elements[i];
e.parentNode.replaceChild(replaceTag, e);
};
Here is one crazy regex which matches what you want:
var text='<div id="main"><div class="replace">< **My Text** ></div><div>Test</div></div>'
var r = /(<(div|DIV)\s+class\s*?=('|")\s*?replace('|")\s*?>)(\s*?<)(.*?)(>\s*?)(<\/(div|DIV)\s*?>)/g;
The whole replacement can be made with:
text.replace(r, function () {
return 'Hello' + arguments[6] + 'Hello';
});
Please let me know if there are issues with the solution :).
Btw: I'm totally against regexes like the one in the answer...If you have made it with that complex regex there's probably better way to handle the problem...
Consider using the DOM instead; you already have the structure you want, so swap out the node itself (borrowing heavily from #maxwell's code, but moving children around as well):
var elements = document.getElementsByClassName('replace');
for(var i = elements.length-1; i>= 0; --i) {
var element = elements[i];
var newElement = document.createElement('replacetext');
var children = element.childNodes;
for(var ch = 0; ch < children.length; ++i) {
var child = children[ch];
element.removeChild(child);
newElement.appendChild(child);
}
element.parentNode.insertBefore(newElement,element);
element.parentNode.removeChild(element);
}
For each element of the given class, then, it will move each of its children over to the new element before using that element's position to insert the new element and finally removing itself.
My only questionmark is whether the modification of items in the array return by getElementByClassName will cause problems; it might need an extra check to see if the element is valid before processing it, or you may prefer to write this as a recursive function and process the tree from deepest node first.
It may seem like more work, but this should be faster (no re-parsing of the html after you've changed it, element moves are just reference value assignments) and much more robust. Attempting to parsing HTML may damage your health.
Rereading the question (always a good plan), you begin with the text in a string. If that is truly the start point (i.e. you're not just pulling that out of an innerHTML value), then to use the above just create a temporary parent element:
var fosterer = document.createElement('div');
fosterer.innerHTML = text; // your variable from the question
And then proceed using fosterer.getElementsByClassName.
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>";
}
I have been trying forever but it is just not working, how can I check the array of urls I got (document.getElementsByTagName('a').href;) to see if any of the websites are in another array?
getElementByTagName gives you a nodelist (an array of nodes).
var a = document.getElementsByTagName('a');
for (var idx= 0; idx < a.length; ++idx){
console.log(a[idx].href);
}
I really suggest that you use a frame work for this, like jquery. It makes your life so much easier.
Example with jquery:
$("a").each(function(){
console.log(this.href);
});
var linkcheck = (function(){
if(!Array.indexOf){
Array.prototype.indexOf = function(obj){
for(var i=0; i<this.length; i++){
if(this[i]===obj){
return i;
}
}
return -1;
}
}
var url_pages = [], anchor_nodes = []; // this is where you put the resulting urls
var anchors = document.links; // your anchor collection
var i = anchors.length;
while (i--){
var a = anchors[i];
anchor_nodes.push(a); // push the node object in case that needs to change
url_pages.push(a.href); // push the href attribute to the array of hrefs
}
return {
urlsOnPage: url_pages,
anchorTags: anchor_nodes,
checkDuplicateUrls: function(url_list){
var duplicates = []; // instantiate a blank array
var j = url_list.length;
while(j--){
var x = url_list[j];
if (url_pages.indexOf(x) > -1){ // check the index of each item in the array.
duplicates.push(x); // add it to the list of duplicate urls
}
}
return duplicates; // return the list of duplicates.
},
getAnchorsForUrl: function(url){
return anchor_nodes[url_pages.indexOf(url)];
}
}
})()
// to use it:
var result = linkcheck.checkDuplicateUrls(your_array_of_urls);
This is a fairly straight forward implementation of a pure JavaScript method for achieving what I believe the spec calls for. This also uses closures to give you access to the result set at any time, in case your list of urls changes over time and the new list needs to be checked. I also added the resulting anchor tags as an array, since we are iterating them anyway, so you can change their properties on the fly. And since it might be useful to have there is a convenience method for getting the anchor tag by passing the url (first one in the result set). Per the comments below, included snippet to create indexOf for IE8 and switched document.getElementsByTagName to document.links to get dynamic list of objects.
Using Jquery u can do some thing like this-
$('a').each(function(){
if( urls.indexOf(this.href) !- -1 )
alert('match found - ' + this.href );
})
urls is the your existing array you need to compare with.