Wrapping a string in a div in pure javascript - javascript

Is there a way in pure javascript to wrap a nacked string?
I have a string that I'm splitting based on a character to separate the header from the rest of the content. I would very much like to style that header, but i can't seem to find a good way to wrap a div around it with a class.
All I can seem to find is wrapping a div around something that already has other elements.
My code looks like this
var string = "Title*This is the very long content";
var title = string.split('*')[0]
var body = string.split('*')[1]
//put them back together
string = title + body;

but i can't seem to find a good way to wrap a div around it with a
class?
You can create an element (which is at the end a tag HTML) with createElement
and attach it a class with className
let string = "Title*This is the very long content";
/*
let title = string.split('*')[0]
let body = string.split('*')[1]
*/
let [title, body] = string.split('*'); // Destructuring assignment
let headerTitle = document.createElement('h1');
headerTitle.textContent = title;
headerTitle.className = "red";//headerTitle.classList.add('red');
let bodyHTML = document.createElement('p');
bodyHTML.textContent = body;
document.querySelector('#content').innerHTML = headerTitle.innerHTML +"<br/>"+ bodyHTML.innerHTML;
.red{
color: red;
}
<div id="content" />
Tip Try to avoid var keyword for declaring variable and replace them with either let or const and better using Destructuring assignment

Related

js: how to simplify html string

is there any way to simplify the HTML string? Like removing all redundant tags from the string.
For instance:
Source HTML:
<div><span><span>1</span></span><span>2</span></div>
Expected output:
<div><span>12</span></div>
(or even less)
<div>12</div>
I've known some libs like quilljs can do this, but it's a huge library, kind of overkill for my case.
also, https://github.com/htacg/tidy-html5 is kind of what I want, but it does not have a js release
You can try using the DOMParser:
let s = `<div><span><span>1</span></span><span>2</span></div>`
let d = new DOMParser()
let doc = d.parseFromString(s, 'application/xml')
let tag = doc.children[0].tagName
let text = doc.children[0].textContent
let result = `<${tag}>${text}</${tag}>`
console.log(result)
Please refer to the below code, It may help you to go further.
var childs = document.querySelectorAll("div#parent")
var tmpTexts = []
for (const c of childs) {
if (tmpTexts.includes(c.innerText)) continue
tmpTexts.push((c.innerText).trim())
c.parentNode.removeChild(c)
}
tmpTextArr = tmpTexts[0].split('\n');
console.log(tmpTextArr);
const para = document.createElement("div");
tmpTextArr.forEach(function(text) {
var node = document.createElement("div");
var nodeTxt = document.createTextNode(text);
node.appendChild(nodeTxt);
para.appendChild(node)
});
document.body.appendChild(para);
https://jsfiddle.net/Frangly/pnLgr8ym/66/
In tmpTexts, for every new line - you should add a div tag.
Create a new Element and iterate the tmpTexts array and a div tag by using innerHTML

Most efficient way to create a div with several children

I'm trying to create a function which takes an object with a few parameters and returns a newly created div.
From what i can see, there seem to be two main ways to accomplish this:
creating each element by itself and appending it
creating a template literal and set the divs innerHTML
the inputs of the functions are not user generated, so i don't think using template literals will create a security issue (please educate me if i'm wrong)
So now my questions are the following:
is one more efficient than the other?
is one preferred?
are there any other concerns?
is there an even more efficient/better way?
below you can see the two solutions i've come up with.
function createDiv (entry) {
const div = document.createElement('div')
div.classList.add('exchange')
div.id = entry.exchange
const img = document.createElement('img')
img.src = `/static/img/${entry.img}.png`
img.alt = entry.name
img.classList.add('logo-image')
div.appendChild(img)
const link = document.createElement('a')
link.href = entry.url
link.classList.add('name')
link.innerText = entry.name
div.appendChild(link)
const routing = document.createElement('span')
routing.innerText = entry.routing ? entry.routing : ''
div.appendChild(routing)
const price = document.createElement('span')
price.innerText = entry.price
price.classList.add('price')
div.appendChild(price)
return div
}
function createDiv (entry) {
const div = document.createElement('div')
div.classList.add('exchange')
div.id = entry.exchange
let text = `
<img class="logo-image" src="/static/img/${entry.img}.png" alt="${entry.name}">
<a class="exchange-name" href="${entry.url}">${entry.name}</a>
<span>${routing.innerText = entry.routing ? entry.routing : ''}</span>
<span class="price">${entry.price}</span>
`
div.innerHTML = text
return div
}
Thank you in advance!
What about doing something like the following?
const createDiv = ({ exchange, img, name, url, routing: entryRouting, price }) => {
return `
<div class="exchange" id="${exchange}">
<img class="logo-image" src="/static/img/${img}.png" alt="${name}">
<a class="exchange-name" href="${url}">${name}</a>
<span>${routing.innerText = entryRouting || ''}</span>
<span class="price">${price}</span>
</div>
`;
}
In this case you are getting the full power of the template literals and of the object destructing.
About the values, you should validate them in some way before storing in the database and sanitize the HTML before getting it back. Some sort of easy validation with regex could be enough for validation. For sanitizing you can choose one of the many libraries like the this https://www.npmjs.com/package/sanitize-html.
About performances, I wouldn't take it too seriously until you do many iterations. As far as I see it is a onetime function call. So I would go for the cleaner way: template strings. But if you are curious, the template string is the fastest. The first approach is almost 100% slower. You can check the results of the test I did over 100 iterations here https://jsbench.me/7gkw1t31rs/2.
Remember that the approach I am telling you will need an innerHTML once the createDiv function returns its value.

How can I append the word variable to my div?

I guess it will not let me because it is returning a string. The error I get is "Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'". How can I write this piece of code correctly?
getWord() {
let words = ["Movies", "Series", "DC Comics", "Batman"];
let word = words[Math.floor(Math.random() * words.length)];
let div = document.createElement("div");
div.appendChild(word);
}
Try div.innerText = word. Because you are trying to insert a String as a node.
If you want to stick with the div.appendChild() so that you could change the styling or element tag name of the text node in the future, you could create a text node and append it to the div instead, like so:
var text = document.createTextNode(word);
div.appendChild(text);
in your example you trying append string in the element, it's not correct, an argument for appendChild method should be element, for example:
const parent = document.createElement("div");
parent.appendChild(document.createElement("div"));
For your case, when you need to add content to the element, you should use textNode:
const title = document.createElement("H1");
const text = document.createTextNode("Movies");
title.appendChild(text);
Or:
const title = document.createElement("H1");
title.textContent = "Series";

splitting an html line into separate variables with JS

In pure javascript (not using JQuery/dojo/etc), what is the best/easiest/quickest way to split a string, such as
var tempString = '<span id="35287845" class="smallIcon" title="time clock" style="color:blue;font-size:14px;" contenteditable="false">cookie</span>';
into
var id = 'id="35287845"';
var class = 'class="smallIcon"';
var title = 'title="time clock"';
var style = 'style="color:blue;font-size:14px;"';
var contenteditable = 'contenteditable="false"';
Things to note:
a "space" cannot be used as a proper delimiter, since it may appear in a value, such as title, above (time clock).
maintaining the double quotes around each variable, such as id="35287845" is important
the opening/closing span tags can be discarded, as well as the content, which in this case, is "cookie"
Here is one approach, which is to place the input string as innerhtml into a javascript created dom element and then leverage the attributes array
//Input html string
var tempString = '<span id="35287845" class="smallIcon" title="time clock" style="color:blue;font-size:14px;" contenteditable="false">cookie</span>';
//make element to contain html string
var tempDiv = document.createElement("div");
//place html string as innerhtml to temp element
tempDiv.innerHTML = tempString;
//leverage attributes array on element
var attributeArray = tempDiv.firstChild.attributes;
//log results
console.log(attributeArray);
Note that you may now do something like
var classString = attributeArray.class;
or
var titleString = attributeArray.title;
Edit
Here is a function that will do it:
function getAttributesFromString(htmlString)
{
var tempDiv = document.createElement("div");
tempDiv.innerHTML = htmlString;
return tempDiv.firstChild.attributes;
}
I think you are trying to get the properties in the span, check this response telling you how to do it.
Get all Attributes from a HTML element with Javascript/jQuery
also you could get the properties and make the string concatenating the the values with your strings.
(You can fin a explanation in pure javascript there)

How to correctly use innerHTML to create an element (with possible children) from a html string?

Note: I do NOT want to use any framework.
The goal is just to create a function that will return an element based on an HTML string.
Assume a simple HTML Document like such:
<html>
<head></head>
<body>
</body>
</html>
All functions mentioned are in included the head section and all DOM creation/manipulation is done at the end of the body in a script tag.
I have a function createElement that takes a well formed HTML String as an argument. It goes like this:
function createElement(str)
{
var div = document.createElement('div');
div.innerHTML = str;
return div.childNodes;
}
Now this functions works great when you call it like such:
var e = createElement('<p id="myId" class="myClass">myInnerHTML</p>');
With the minor (possibly HUGE) problem that the element created isn't a 'true' element, it still has a parentNode of 'div'. If anyone knows how to fix that, then that would be awesome.
Now if I call the same function with a more complex string:
var e = createElement('<p id="myId" class="myClass">innerHTML<h2 id="h2ID" class="h2CLASS">Heading2</h2></p>');
It creates TWO children instead of ONE child with another child having another child.Once you do div.innerHTML = str. The innerHTML instead of
`<p id="myId" class="myClass">innerHTML <h2 id="h2ID" class="h2CLASS">Heading2</h2> </p>`
turns to
`<p id="myId" class="myClass">innerHTML</p> <h2 id="h2ID" class="h2CLASS">Heading2</h2>`
Questions:
Can I somehow get an element without a parent node after using .innerHTML?
Can I (in the case of the slightly complex string) get my function to return ONE element with the appropriate child instead of two elements. [It actually returns three, <p.myClass#myId>,<h2.h2CLASS#h2ID>, and another <p>]
This is similar to the answer from palswim, except that it doesn't bother with creating a clone, and uses a while() loop instead, always appending the node at [0].
function createElement( str ) {
var frag = document.createDocumentFragment();
var elem = document.createElement('div');
elem.innerHTML = str;
while (elem.childNodes[0]) {
frag.appendChild(elem.childNodes[0]);
}
return frag;
}
You'd have to attach the new element somewhere. Try using a DocumentFragment object in conjunction with the div you created:
function createElement(str) {
var div = document.createElement('div');
div.innerHTML = str;
var container = document.createDocumentFragment();
for (var i=0; i < div.childNodes.length; i++) {
var node = div.childNodes[i].cloneNode(true);
container.appendChild(node);
}
return container.childNodes;
}
It's more overhead, but it does what you want. Note that DOM elements' .insertAdjacentHTML member function is coming in HTML5.
For that complex string you passed, it isn't valid XHTML syntax - you can't have a block element as a child of <p> (<h2> is a block level element).

Categories

Resources