Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Passing Nodes to template literal & rendering it?

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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?

>Solution :

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!">
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading