I have a function returning a template literal:
function generateStuff(nodes) {
const output = `<ul>${nodes}</ul>`;
return document.body.innerHTML = output;
}
nodes
is an array of <li>
elements made with createElement
and then added to nodes
via appendChild
.
Is there a way of render a list with generateStuff(nodes)
? Right now all it returns is <ul>[object NodeList]</ul>
and I just want it to return proper HTML with working links etc.
I suppose I need to parse it somehow but as this is JS and NodeList is native to it maybe there's a method in place for it already?
Is there a way of render a list with generateStuff(nodes)?
Yes, but I'd consider changing how you're doing this instead. But the way you'd do it is with a round-trip through HTML:
function generateStuff(nodes) {
const output = `<ul>${Array.from(nodes, (node) => node.outerHTML)}</ul>`;
return (document.body.innerHTML = output);
}
But that's inefficient and lossy (loses event handlers on the nodes, for instance). Instead of using a template literal, consider appending the nodes directly:
function generateStuff(nodes) {
const ul = document.createElement("ul");
for (const node of nodes) {
ul.appendChild(node);
}
// Or replace the loop with: `ul.append(...nodes)`
document.body.innerHTML = "";
document.body.appendChild(ul);
return ul.outerHTML; // **If** you really need to return HTML, but hopefully not
}
In a comment you've said:
I think I might have overly simplified my case, normally I wouldn't have use template literal here but instead of I have like 20 nested containers there. Your second approach seems really cool but what if ul is inside of a x different containers? How do I append to then? Do I still have to manually create and append every single one of them? That's what I'm trying to avoid here.
You could create the structure by assigning to innerHTML
with a means of identifying the ul
, then once the structure exists, do the append:
function generateStuff(nodes) {
// Create a new replacement `body` element
const body = document.createElement("body");
// Create the structure
body.innerHTML = "<ul class='target'></ul>";
// Get the `ul` and append to it
const ul = body.querySelector(".target");
ul.append(...nodes);
// Replace the element
document.body.replaceWith(body);
// **If** you really need to return HTML
return document.body.innerHTML;
}
Live Example:
document.querySelector("input[type=button]").addEventListener("click", () => {
const nodes = Array.from({length: 5}, (_, i) => {
const li = document.createElement("li");
li.textContent = "li #" + i;
return li;
});
generateStuff(nodes);
});
function generateStuff(nodes) {
// Create a new replacement `body` element
const body = document.createElement("body");
// Create the structure
body.innerHTML = "<ul class='target'></ul>";
// Get the `ul` and append to it
const ul = body.querySelector(".target");
ul.append(...nodes);
// Replace the element
document.body.replaceWith(body);
// **If** you really need to return HTML
return document.body.innerHTML;
}
<input type="button" value="Go!">