Passing html nodes to a javascript function - javascript

I'm new to JavaScript and am trying to create a recursive function that checks if two DOM nodes are equivalent. This function seems to be returning true for everything and isn't checking the DOM the way I want it to for some reason. Only nodes 1 & 4 are equivalent.
var htmlStrings = ['<div id="one">Some<span>node <em>contents</em> for</span>comparison</div>', '<div id="two">Some<span>node contents for</span>comparison</div>', '<div id="one">Some<span>node <strong>contents</strong> for</span>comparison</div>', '<div id="four">Some<span>node <em>contents</em> for</span>comparison</div>'];
var div1 = document.createElement('div');
div1.innerHTML = htmlStrings[0];
document.body.appendChild(div1);
var div2 = document.createElement('div');
div2.innerHTML = htmlStrings[1];
document.body.appendChild(div2);
var div3 = document.createElement('div');
div3.innerHTML = htmlStrings[2];
document.body.appendChild(div3);
var div4 = document.createElement('div');
div4.innerHTML = htmlStrings[3];
document.body.appendChild(div4);
function nodeEquivalence(node1, node2) {
var passed = false;
if (node1.nodeType === node2.nodeType) {
if ((node1.tagName === node2.tagName && node1.nodeValue === node2.nodeValue)) {
passed = true;
}
}
node1 = node1.firstChild;
node2 = node2.firstChild;
while (node1 && node2) {
nodeEquivalence(node1, node2);
node1 = node1.nextSibling;
node2 = node2.nextSibling;
}
return passed;
}
console.log(nodeEquivalence(div1, div2));
console.log(nodeEquivalence(div1, div4));

You're passing strings, not DOM elements. You need to convert the HTML to DOM elements. There are many solutions described at
Creating a new DOM element from an HTML string using built-in DOM methods or prototype
So you can do:
var html1 = '<div id="one">Some<span>node <em>contents</em> for</span>comparison</div>';
var html2 = '<div id="four">Some<span>node <em>contents</em> for</span>comparison</div>';
var html3 = '<div id="one">Some<span>node <b>contents</b> for</span>comparison</div>';
var div1 = document.createElement('div');
div1.innerHTML = html1;
var div2 = document.createElement('div');
div2.innerHTML = html2;
var div3 = document.createElement('div');
div3.innerHTML = html3;
alert(nodeEquivalence(div1.firstChild, div2.firstChild));
alert(nodeEquivalence(div1.firstChild, div3.firstChild));
function nodeEquivalence (node1, node2) {
var passed = true;
function test(node1, node2) {
if ((node1.nodeType === node2.nodeType) && (node1.tagName === node2.tagName || node1.nodeValue === node2.nodeValue) && (node1.childNodes.length === node2.childNodes.length)) {
passed = true;
} else {
passed = false;
}
}
node1 = node1.firstChild;
node2 = node2.firstChild;
while (passed && node1 && node2) {
test(node1, node2);
node1 = node1.nextSibling;
node2 = node2.nextSibling;
}
//test(document.body);
return passed;
};

Use document.createElement(*tagName*)
Here is some documentation.
For example, you'll want to create two elements, pass them both in and see if they're equivalent. And then you can base the same one in twice.
var newDiv = document.createElement("div");
var newSpan = document.createElement("span");

yes, instead of comparing 2 html elements, you are simply comparing 2 strings. And your node1, node2 will always be undefined.
by the way, this following has some nice examples as to how to compare 2 html elements.
How to compare two HTML elements

Most of the relevant part is innerHTML. Most of the information is in there. If the innerHTML of the two HTML nodes are the same, than nearly everything is the same. Than the tagName and for <input> tags the type attribute:
function nodeEquivalence(node1, node2) {
var equal = false;
if (node1.innerHTML === node2.innerHTML) {
if (node1.tagName === node2.tagName) {
if (node1.type === node2.type) {
equal = true;
}
}
}
return equal;
}
I think, this function will catch nearly all cases.
Note that there is a little difference, if you access the node via id or class name:
var el = document.getElementById(id);
el.innerHTML
var el2 = document.getElementsByClassName(className);
el[0].innerHTML;
Also, you can compare by outerHTML. When you give each HTML node the same class name, you will have the exact same thing.
Example
Create a HTML element:
var div = document.createElement("div");
var text = document.createTextNode("some text");
div.appendChild(text);
document.body.appendChild(div);

Related

$ dot each not working for recursion (JS)

I have a loop in which I am calling rec_append() recursively, apparently the first pass alone works, then the loop stops.
I have an array of 4 elements going into that $.each loop but I see only the first element going into the function recursively. Help!
I switched it for a element.forEach but that gives me only the second element and I am stuck, is there a better solution to process a tree of elements? My array is a part of a tree.
var data = JSON.parse(JSON.stringify(result))
var graph = $(".entry-point");
function rec_append(requestData, parentDiv) {
var temp_parent_details;
$.each(requestData, function (index, jsonElement) {
if (typeof jsonElement === 'string') {
//Element construction
//Name and other details in the form of a : delimited string
var splitString = jsonElement.split(':');
var details = document.createElement("details");
var summary = document.createElement("summary");
summary.innerText = splitString[0];
details.append(summary);
temp_parent_details = details;
parentDiv.append(details);
var kbd = document.createElement("kbd");
kbd.innerText = splitString[1];
summary.append(' ');
summary.append(kbd);
var div = document.createElement("div");
div.className = "col";
details.append(div);
var dl = document.createElement("dl");
div.append(dl);
var dt = document.createElement("dt");
dt.className = "col-sm-1";
dt.innerText = "Path";
div.append(dt);
var dd = document.createElement("dd");
dd.className = "col-sm-11";
dd.innerText = splitString[2];
div.append(dd);
var dt2 = document.createElement("dt");
dt2.className = "col-sm-1";
dt2.innerText = "Type";
div.append(dt2);
var dd2 = document.createElement("dd");
dd2.className = "col-sm-11";
dd2.innerText = splitString[1];
div.append(dd2);
} else {
$.each(jsonElement, function (jsonElementArrIndx, jsonChildElement) {
rec_append(jsonChildElement, temp_parent_details); //Only 1 pass works, rest skip
});
}
});
}
rec_append(data, graph);
Sample data:enter image description here

After concatenating html elements the result variable return 0

here is my code it return 0 when i call result variable i want to add elements in html without DOM, means i want to re-create this whole html in JS using this code.
var div = document.createElement("div");
div.setAttribute("id", "old");
var newDiv = document.createElement("div");
newDiv.setAttribute("id", "new");
var p = document.createElement("p");
p.setAttribute("id", "paragraph")
var domDiv = document.getElementById("old");
var domNewDiv = document.getElementById("new");
var domP = document.getElementById("paragraph");
var result = domDiv + domNewDiv + domP;
result;
Code in console
document.getElementById returns a Javascript Object. You cannot simply concatenate objects. But you can concatenate the html content of those objects for example:
var result = domDiv.innerHTML + domNewDiv.innerHTML + domP.innerHTML;

document not defined error javascript

I'm learning javascript and have created some HTML within my javascript file so as to test a simple function that takes in nodes as parameters. I keep getting a 'document not defined' error. What do I need to do within my JS file/code to define the document?
I already tried things listed here:
ReferenceError: document is not defined (in plain JavaScript)
var div1 = document.createElement("div");
var text1 = document.createTextNode('<div id="one">Some<span>node <em>contents</em> for</span>comparison</div>');
div1.appendChild(text1);
document.body.appendChild(div1);
var div2 = document.createElement("div");
var text2 = document.createTextNode('<div id="two">Some<span>node contents for</span>comparison</div>');
div2.appendChild(text2);
document.body.appendChild(div2);
var div3 = document.createElement("div");
var text3 = document.createTextNode('<div id="one">Some<span>node <strong>contents</strong> for</span>comparison</div>');
div3.appendChild(text3);
document.body.appendChild(div3);
var div4 = document.createElement("div");
var text4 = document.createTextNode('<div id="four">Some<span>node <em>contents</em> for</span>comparison</div>');
div4.appendChild(text4);
document.body.appendChild(div4);
function nodeEquivalence(node1, node2) {
var equal = false;
if (node1.innerHTML === node2.innerHTML) {
if (node1.tagName === node2.tagName) {
if (node1.type === node2.type) {
equal = true;
}
}
}
return equal;
}
console.log(nodeEquivalence(div1, div4));
Don't use innerHTML. Use createTextNode or textContent.
Create HTML element the right way:
var div = document.createElement("div");
var text = document.createTextNode("some text");
div.appendChild(text);
document.body.appendChild(div);
Your function is too complicated to compare to HTML nodes. This function
function nodeEquivalence(node1, node2) {
var equal = false;
if (node1.innerHTML === node2.innerHTML) {
if (node1.tagName === node2.tagName) {
if (node1.type === node2.type) {
equal = true;
}
}
}
return equal;
}
is much easier.

Javascript RegEx - Split Html-string

I'm working on a script and need to split strings which contain both html tags and text. I'm trying to isolate the text and elimanate the tags
For example, I want this:
string = '<p><span style="color:#ff3366;">A</span></p><p><span style="color:#ff3366;text-decoration:underline;">B</span></p><p><span style="color:#ff3366;text-decoration:underline;"><em>C</em></span></p>';
to be split like this:
separation = string.split(/some RegExp/);
and become:
separation[0] = "<span style="color:#ff3366;">A</span>";
separation[1] = "<span style="color:#ff3366;text-decoration:underline;">B</span>";
separation[2] = "<span style="color:#ff3366;text-decoration:underline;"><em>C</em></span>";
After that I would like to split the sepeartion string like this:
stringNew = '<span style="color:#ff3366;">A</span>';
extendedSeperation = stringNew.split(/some RegExp/);
extendedSeperation[0] = "A";
extendedSeperation[1] = "style="color:#ff3366;";
Don't use RegEx for reasons explained in comments.
Instead, do this:
Create an invisible node:
node = $("<div>").css("display", "none");
Attach it to the body:
$("body").append(node);
Now inject your HTML into the node:
node.html(myHTMLString);
Now you can traverse the DOM tree and extract/render it as you like, much like this:
ptags = node.find("p") // will return all <p> tags
To get the content of a tag use:
ptags[0].html()
Finally, to clear the node do:
node.html("");
This should be enough to get you going.
This way you leverage the internal parser of the browser, as suggested in the comments.
Your exact expectations are a little unclear, but based only on the information given here is an example that may give you ideas.
Does not use RegExp
Does not use jQuery or any other library
Does not append and remove elements from the DOM
Is well supported across browsers
function walkTheDOM(node, func) {
func(node);
node = node.firstChild;
while (node) {
walkTheDOM(node, func);
node = node.nextSibling;
}
}
function textContent(node) {
if (typeof node.textContent !== "undefined" && node.textContent !== null) {
return node.textContent;
}
var text = ""
walkTheDOM(node, function (current) {
if (current.nodeType === 3) {
text += current.nodeValue;
}
});
return text;
}
function dominate(text) {
var container = document.createElement('div');
container.innerHTML = text;
return container;
}
function toSeparation(htmlText) {
var spans = dominate(htmlText).getElementsByTagName('span'),
length = spans.length,
result = [],
index;
for (index = 0; index < length; index += 1) {
result.push(spans[index].outerHTML);
}
return result;
}
function toExtendedSeperation(node) {
var child = dominate(node).firstChild,
attributes = child.attributes,
length = attributes.length,
text = textContent(child),
result = [],
style,
index,
attr;
if (text) {
result.push(text);
}
for (index = 0; index < length; index += 1) {
attr = attributes[index]
if (attr.name === 'style') {
result.push(attr.name + '=' + attr.value);
break;
}
}
return result;
}
var strHTML = '<p><span style="color:#ff3366;">A</span></p><p><span style="color:#ff3366;text-decoration:underline;">B</span></p><p><span style="color:#ff3366;text-decoration:underline;"><em>C</em></span></p>',
separation = toSeparation(strHTML),
extendedSeperation = toExtendedSeperation(separation[0]),
pre = document.getElementById('out');
pre.appendChild(document.createTextNode(JSON.stringify(separation, null, 2)));
pre.appendChild(document.createTextNode('\n\n'));
pre.appendChild(document.createTextNode(JSON.stringify(extendedSeperation, null, 2)));
<pre id="out"></pre>
Of course you will need to make modifications to suit your exact needs.

JS - text value of tag - when tag is string

How can I get text value of a tag when tag is stored as string?
var value = "<div>teeext</div>";
tag can be anything, its attributes may contain ">" string as well, regexp can be dangerous - also text value itself can be another tag.
You can make a dummy element:
var value = "<div>teeext</div>";
var div = document.createElement('div');
div.innerHTML = value;
var text = div.innerText || div.textContent;
Using just javascript:
var div = document.createElement('div');
var value = "<div>teeext</div>";
div.innerHTML = value;
var element = div.firstChild
console.log(element.innerHTML); //this the stuff in the tag
Using jquery:
$(value).html();
I guess that you're trying to strip tags.. In that case you can do it like this:
originalString = "<div>teeext</div>";
var value = originalString.replace(/(<([^>]+)>)/ig,"");
Test it out. If there are any exceptions which you need to handle, then just comment here and I'll try to help you further.
Edit for multiple tags:
originalString = "<div>teeext</div>";
outputString = originalString;
while (outputString.indexOf(/(<([^>]+)>)/ig) !== -1){
outputString = outputString.replace(/(<([^>]+)>)/ig,"");
}
value = outputString;
Haven't tested it, but you get the point ;)
Does this help as a starter?
function getText(tagString) {
var firstOpenTag = tagString.indexOf(">"),
lastCloseTag = tagString.lastIndexOf("</"),
substrLength;
if (firstOpenTag == -1 || lastCloseTag == -1) {
return tagString;
}
substrLength = (tagString.length - firstOpenTag) - (tagString.length - lastCloseTag) - 1;
return tagString.substr(firstOpenTag + 1, substrLength);
}
var value = "<div>teeext</div>";
console.log(getText(value));
var moreTags = "<div><ul><li>Text</li></ul></div>",
returnValue = moreTags,
prevReturnValue = "";
while (returnValue !== prevReturnValue) {
prevReturnValue = returnValue;
returnValue = getText(returnValue);
}
console.log(returnValue);

Categories