Can I convert an HTML comment to actual HTML using JavaScript? - javascript

If I insert a comment node into a document fragment, can I convert it to HTML later? Example:
var fragment = document.createDocumentFragment();
var comment = document.createComment('<div>Testing</div>');
fragment.appendChild(comment);
// Convert comment into actual HTML?
What this would look like inside of a fragment:
<!--<div>Testing</div>-->
And how it should be when done (actual DOM):
<div>Testing</div>
Background:
There are many limitations for inserting HTML into a fragment. Fragments don't support innerHTML or insertAdjacentHTML etc. There are other methods for getting HTML into fragments, but they drop certain elements and leave only the inner text. For example, creating a fragment with the createRange API drops those types of nodes and I will be left with a fragment with just the text node "Data"
var fragment = document.createRange().createContextualFragment('<td>Data</td>');
The hope is that if I can convert a comment into actual DOM, that it will work as expected.

For the entire body you can use that snippet:
var body = document.getElementsByTagName('body')[0],
bodyHtml = body.innerHTML;
while (bodyHtml.indexOf("<!--") !== -1) { // will replace all the comments with empty string
bodyHtml = bodyHtml.replace("<!--", "").replace("-->", "");
}
body.innerHTML = bodyHtml;
Hello
<h1>hi</h1>
<!--<div>Testing</div>-->
<!--<div>Testing</div>-->

It sounds like your underlying problem is that you need to stuff HTML text into a DocumentFragment, so here is a helper function to do so for you.
var container = document.createElement('div')
function createFragmentWithHTML (html, doc) {
var result = (doc || document).createDocumentFragment()
container.innerHTML = html
while (container.firstChild) result.appendChild(container.firstChild)
return result
}
var fragment = createFragmentWithHTML('<div>Testing</div><p><strong>More text</strong></p>')
// do whatever you want with `fragment`
document.body.appendChild(fragment)

Something like this would do the trick
var element = document.getElementById("whatever"); // get the parent element
var comment = element.innerHTML; // get the thml
var html = comment.replace("<!--", "").replace("-->", ""); // remove the comment
element.innerHTML = html;

Text content of an HTML comment can be accessed via the nodeValue property of the Node interface or the data property of the CharacterData interface that the HTML Comment interface inherits from:
<!--<div>Example</div>-->
var code = comment.data; /* Now contains `<div>Example</div>` text */
var code = comment.nodeValue; // Same result.
Fwiw, I have a blog post about using HTML comment as data container.

You can get your comments with element.childNodes method, then use textContent method to get the content of comment, then change it into HTML Element with innerHTML method, then remove the comment node and replace it with Element Node.
parseComments('container');
function parseComments(getContainerId){
var container = document.getElementById(getContainerId);
var nodes = container.childNodes;
for(var i=0;i<nodes.length;i++){
if(nodes[i].nodeType===8){
var virtualCont = document.createElement('DIV');
var getContent = nodes[i].textContent;
virtualCont.innerHTML = getContent;
container.removeChild(nodes[i]);
if(nodes[i+1]){
container.insertBefore(virtualCont.children[0],nodes[i+1]);
} else {
container.appendChild(virtualCont.children[0]);
}
}
}
}
<div id="container">
<h1>some header A</h1>
<!--<p>some hidden content A</p>-->
<p>some content</p>
<!--<p>some hidden content B</p>-->
<p>another content</p>
<!--<h1>some hidden header B</h1>-->
<!--<p>another hidden content C</p>-->
</div>

Related

make a DOM element's content be the one of a document fragment

I am trying to insert into a DOM element the content of a document fragment (in pure javascript). The working principle is this:
var a = document.getElementById("a"),
b = document.getElementById("b");
now i place the content of "a" into a document fragment, using a template element
var content = document.createElement("template");
content.innerHTML = a.innerHTML;
content = content.content.cloneNode(true);
now i would like to replace the content of b with the content of content. I tried with a simple b.innerHTML = content.innerHTML;, but it seems like if document fragments doesn't have innerHTML property.
Is this possible to do?
Note: i know this is totally an ineffective way to do the task of making b.innerHTML = a.innerHTML, but obviously this is just a simplification of a bigger task i am managing to do.
You need to create "clones" and by using the template content property you can then use the innerHTML of a and b into your fragments.
Example:
const a = document.getElementById("a"),
b = document.getElementById("b");
// note template will only be parsed, to render it use js...
function initTemplate() {
const container = document.getElementById("container");
const template = document.getElementById("t");
// create a first clone with the innerHTML of a...
const firstClone = template.content.cloneNode(true);
firstClone.textContent = a.innerHTML;
// create a second clone with the innerHTML of b...
const secondClone = template.content.cloneNode(true);
secondClone.textContent = b.innerHTML;
// append to the document
container.appendChild(firstClone);
container.appendChild(secondClone);
}
<p id="a">Paragraph A</p>
<p id="b">Paragraph B</p>
<button onclick="initTemplate()">Init Template</button>
<br>
<div id="container"></div>
<template id="t">
</template>
If you want to check if your browser supports the HTML template element, do something like this:
if ("content" in document.createElement("template") {
// clone the elements as above and append them to the document
}
Mozilla Docs and Mozilla Docs

Changing HTML in JavaScript without innerHTML

Let's say my code was something pretty simple like this:
let content = "";
for(let i=0; i<array.length; i++){
content+='<h1>array[i]</h1>';
}
document.getElementById('some_id').innerHTML = content;
I don't like the idea of putting HTML in my JavaScript code, but I don't know any other way of inserting elements into the DOM without using innerHTML, JQuery's html() method, or simply creating new DOM elements programmatically.
In the industry or for best practices, what's the best way to insert HTML elements from JavaScript?
Thanks in advance!
You can use a DOMParser and ES6 string literals:
const template = text => (
`
<div class="myClass">
<h1>${text}</h1>
</div>
`);
You can create a in memory Fragment:
const fragment = document.createDocumentFragment();
const parser = new DOMParser();
const newNode = parser.parseFromString(template('Hello'), 'text/html');
const els = newNode.documentElement.querySelectorAll('div');
for (let index = 0; index < els.length; index++) {
fragment.appendChild(els[index]);
}
parent.appendChild(fragment);
Since the document fragment is in memory and not part of the main DOM tree, appending children to it does not cause page reflow (computation of element's position and geometry). Historically, using document fragments could result in better performance.
Source: https://developer.mozilla.org/en-US/docs/Web/API/Document/createDocumentFragment
Basically you can use whatever template you want because it's just a function that return a string that you can feed into the parser.
Hope it helps
You can use the createElement() method
In an HTML document, the document.createElement() method creates the HTML element specified by tagName, or an HTMLUnknownElement if tagName isn't recognized.
Here is an example,
document.body.onload = addElement;
function addElement () {
// create a new div element
var newDiv = document.createElement("div");
// and give it some content
var newContent = document.createTextNode("Hi there and greetings!");
// add the text node to the newly created div
newDiv.appendChild(newContent);
// add the newly created element and its content into the DOM
var currentDiv = document.getElementById("div1");
document.body.insertBefore(newDiv, currentDiv);
}
<!DOCTYPE html>
<html>
<head>
<title>||Working with elements||</title>
</head>
<body>
<div id="div1">The text above has been created dynamically.</div>
</body>
</html>
A flexible and more faster (efficient) way to insert HTML elements using JavaScript's insertAdjacentHTML method. It allows you to specify exactly where to place the element. Possible position values are:
'beforebegin'
'afterbegin'
'beforeend'
'afterend'
Like this:
document.getElementById("some_id").insertAdjacentElement("afterbegin", content);
Here's a Fiddle example
Creating the element programmatically instead of via HTML should have the desired effect.
const parent = document.getElementById('some_id');
// clear the parent (borrowed from https://stackoverflow.com/questions/3955229/remove-all-child-elements-of-a-dom-node-in-javascript)
while (parent.firstChild) {
parent.removeChild(parent.firstChild);
}
// loop through array and create new elements programmatically
for(let i=0; i<array.length; i++){
const newElem = document.createElement('h1');
newElem.innerText = array[i];
parentElement.appendChild(newElem);
}

How to insert multi values to data-tag

I made a jquery filter function, that filtering the results by data-tags. like this:
<div class="resultblock" data-tag="ios">
<img src="images/osx.jpg" class="itemimg">
<div class="desc">
<div class="desc_text">
lorem ipsum
</div>
</div>
i just want to insert in the data-tag another tags to filter. like this:
data-tag="ios,android,windows"
How can i do that?
I am not sure I fully understand the question you are asking, but I think you could accomplish this via JS.
In your html add a script tag and then you just write some JS to edit or add html tags. Here is an example:
<script>
var para = document.createElement("p");
var node = document.createTextNode("This is new.");
para.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(para);
</script>
Now to sort the data-tag:
just add this code to your HTML file.
<div id="div1">
</div>
<script>
var tag ="ios,android,windows"; //initialize variable
var data = tag.split(","); //this makes an array of ios,andrid,windows
var i = 0;
while (i < 3){
alert(i);
var para = document.createElement("p");
var node = document.createTextNode(data[i]);
para.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(para);
i++;
}
</script>
The best way doing this is to use classes. Adding classes and removing them is much easier than other attributes. The classes should not overlap with other classes used for CSS for example. Adding a prefix to them is even better. Like this:
$(".filter-ios").hide(); // hide all ios elements
$("something").addClass("filter-windows"); // add the class windows to an element
$(".filter-ios").addClass("filter-apple"): // add the apple filter class to the ios filter class elements
$("something").hasClass("filter-samsung"); // check if an element has the filter class samsung
// ...
The classes .filter-* should be used for filtering only, they must not have any CSS attached to them, if there is already classes like that, then just change the prefix filter to something else!
I've just created a little object with two methods .add and .remove. It works like classList DOM method for adding and removing classes. If you add one value twice, it's added only once, also if you remove some not existing class, any error will occure. Hope you'll find it helpful.
var el = document.getElementById('myElem');
multiValues = {
add: function(elem,val){
if(elem.constructor.toString().search('HTML')===-1) return;
if(typeof val !=='string') return;
if(!elem.attributes['data-tag']) elem.setAttribute('data-tag');
var attr = elem.attributes['data-tag'];
var parsed = attr.value.split(',');
var isExist = parsed.some(function(a){
return a === val;
});
if(!isExist) parsed.push(val);
elem.setAttribute('data-tag',parsed.join(','));
},
remove: function(elem,val){
if(elem.constructor.toString().search('HTML')===-1) return;
if(typeof val !=='string') return;
if(!elem.attributes['data-tag']) return;
var attr = elem.attributes['data-tag'];
var parsed = attr.value.split(',');
parsed.some(function(a,b){
if(a===val){
parsed.splice(b,1);
}
elem.setAttribute('data-tag',parsed.join(','));
});
}
};
multiValues.add(el,'window');
multiValues.add(el,'window');
multiValues.add(el,'window');
multiValues.add(el,'android');
multiValues.remove(el,'a');
multiValues.remove(el,'b');
multiValues.add(el,'something');
console.log(el.attributes['data-tag'].value);
<div class="resultblock" data-tag="ios" id="myElem"></div>

How to append content to querySelectorAll element with innerHTML/innerText?

I currently have my class element:
var frame_2 = document.querySelectorAll(".name");
Currently this div is empty. I now want to "append/add" some content to that div - I had a go with innerHTML + innerText but for some reason nothing seems to be added.
Example:
frame_2.innerHTML = '<img src="image.gif" />';
and
frame_2.innerText = 'some text';
Any suggestions? Im not sure if there are ways of doing the same - or performance'wise something better?
this gives you a list of elements that contain the class name
var name=document.querySelectorAll(".name");
you want the first element?
name[0].textContent='some text';
This gives you one single element, the first one.
var name=document.querySelector(".name");
name.textContent='some text';
To append stuff
name.appendChild(document.createTextNode('pizza'));
name.appendChild(document.createElement('div')).textContent='spaghetti';
name.appendChild(document.createElement('img')).src='cookie.jpg';
EDIT
To get the elements by classname, then retrieve the id :
var names=document.querySelectorAll(".name"),l;
while(l--){
console.log(names[l].id);
}
or if i didn't understand correctly
html
<div class="spaghetti" id="pizza"></div>
js
document.querySelector(".spaghetti#pizza")
EDIT2
html
<div id="container1"><div class="my-class"></div></div>
js
document.querySelector("#container1>.my-class")
Easier solution, any use case. Query your selector:
let find = document.querySelector('.selector');
create some html as a string
let html = `put your html here`;
create element from string
let div = document.createElement('div');
div.innerHTML = html;
Append new html you created to selector
find.appendChild(div);

DIV with <br> new line text

in my project i have an xmlhttpresponse object with some node, and i need to print element of one (serps) in a div obj but formatted.
Node is like this:
now i have to create a div where store serps info like response.serps1.headline+""+response.serps1.url+""+response.serps2.headline+""+response.serps2.url ecc ecc and in my code i have tried like this:
//Data
var divSerp3 = createElement('div', 'divSerp3', 'divSerp3css');
if (typeof(response.serps) === 'undefined' || response.serps === null) {
tse3 = document.createTextNode("NO DATA");
} else {
tse3 = document.createTextNode(response.serps[1].headline+" <br>"+response.serps[1].url+"<br><br>"+response.serps[2].headline+" <br>"+response.serps[2].url+"<br><br>"+response.serps[3].headline+"<br>"+response.serps[3].url+"<br><br>"+response.serps[4].headline+"<br>"+response.serps[4].url+"<br><br>"+response.serps[5].headline+" <br>"+response.serps[5].url);
}
divSerp3.appendChild(tse3);
but the result is like:
How can i cycle my entire serps node and insert data in a formatted mode into my div??
Html won't be rendered correctly in a TextNode.. as the element's name says by itself, its content is basically textual.
I suggest you to append <br> separately and I would not use createTextNode().. I'd append as many childs as you need using the appropriate html elements (like spans, paragraphs, etc..) and filling their content with $.html('your content') function if you are using jQuery library or element.innerHtml if you are working with pure javascript.
Hope it helps ;)
Instead of creating a text node, create an element and use innerHTML.
var divSerp3 = createElement('div', 'divSerp3', 'divSerp3css');
if (typeof(response.serps) === 'undefined' || response.serps === null) {
tse3 = document.createTextNode("NO DATA");
} else {
tse3 = document.createElement('span');
tse3.innerHTML = response.serps[1].headline+" <br>"+response.serps[1].url+"<br><br>"+response.serps[2].headline+" <br>"+response.serps[2].url+"<br><br>"+response.serps[3].headline+"<br>"+response.serps[3].url+"<br><br>"+response.serps[4].headline+"<br>"+response.serps[4].url+"<br><br>"+response.serps[5].headline+" <br>"+response.serps[5].url);
}
divSerp3.appendChild(tse3);
You're creating a TextNode which will take all of your html and parse it as text. You want to document.createElement('br') and append those instead of doing +"<br><br>"
HTML won't render when inside a text node. See Is it possible to get the the createTextNode method to render html tags?
You could create <br> elements and append them.
Or you could use newlines instead of <br> and use CSS white-space: pre-wrap;

Categories

Resources