An easier way to manage HTML DOM using Javascript
Tags: javascript, html, dom, template
Published: 2022-04-15 14:37:08

Why you should use HTML Code generation methods as a last resort

**Training**

We hire freshers and train them in-house here at [Freshbits](http://freshbits.in). A lot of our own learning happens when we teach basic stuff to them.

Out of that, one of the random [basic stuff](https://blog.freshbits.in/the-correct-way-to-pass-methods-as-event-handlers-in-javascript) that I would like to share today is about HTML code generation using Javascript.


**Examples**

We get the beginners to add some interactivity to the HTML pages that they have built using Javascript. It could be:

- Add to cart functionality on the e-commerce page
- Delete item functionality on the products listing page
- Add address functionality on the checkout page, etc.

Javascript frameworks like React, Vue, or Angular are not in their syllabus yet. They use jQuery or vanilla JS for these kinds of developments.


![Excited to start](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xk0c278sv8efghdkfcwd.gif)

With the fresh opportunity on hand and *limited* working experience, they are generally excited to go for it and come up with something like the following.


**The go-to old way 💩**

I will take the code done by our newest team member, Utsav, as an example. He was given the task of coding the *add to cart* functionality. As we expected, he coded the functionality this way:

```JS
function displayCart() {
    // Abbreviating other stuff to focus on the core topic...

    for (let i = 0; i < cart.length; i++) {
        var imageTag = document.createElement('img');
        imageTag.src = cart[i].img;
        imageTag.setAttribute('class', 'w-10 h-10 object-cover rounded-md');
        document.getElementById('cart-item-' + i).appendChild(imageTag);

        var nameTag = document.createElement('span');
        nameTag.setAttribute('class', 'ml-4 font-semibold text-sm');
        nameTag.innerHTML = cart[i].name;
        document.getElementById('cart-item-' + id).appendChild(nameTag);

        var priceTag = document.createElement('div');
        priceTag.innerHTML = cart[i].price;
        document.getElementById('cart-item-' + id).appendChild(priceTag);

        var deleteTag = document.createElement('button');
        deleteTag.setAttribute('class', 'px-3 py-1 rounded-md bg-red-300 text-white');
        deleteTag.setAttribute('onclick', 'removeFromCart(' + cart[i].id + ')');
        deleteTag.innerHTML = "x";
        document.getElementById('cart-item-' + id).appendChild(deleteTag);

        // ...
    }
}
```

There is nothing wrong with this approach. It is just **less readable and maintainable**. What if we want to add more elements to this cart? What if we wish to change styles?

Some might argue jQuery can make it better. While those long lines of code would be shorter, the main issue still stays there: *managing changes in the final HTML output*

Reading and modifying the HTML directly is easier. Let's see how.


**Another way 🙅**

We can rewrite the same example as the following:

```JS
function displayCart() {
    // Abbreviating other stuff to focus on the core topic...

    for (let i = 0; i < cart.length; i++) {
        var cartItemHtml = [
            '<div id="cart-item-' + i + '">',
                '<img class="w-10 h-10 object-cover rounded-md" src="' + cart[i].img + '" />',
                '<span class="ml-4 font-semibold text-sm">' + cart[i].name + '</span>',
                '<div>' + cart[i].price + '</div>',
                '<button class="px-3 py-1 rounded-md bg-red-300 text-white" onclick="removeFromCart(' + cart[i].id + ')">x</button>',
            '</div>'
        ].join("\n");

        // ...
    }
}
```

There is much better readability now. We can see what the final HTML is gonna look like. But, the HTML code is merged into Javascript so we have to play with those quotes a lot. One step further is to make the HTML code independent.


**Even better way 🤗**

There is a [template](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template) HTML tag that is not shown on the page by default. We can use it to host our HTML code like:

```HTML
<template id="cart-item">
    <div>
        <img class="w-10 h-10 object-cover rounded-md cart-item-image" />
        <span class="ml-4 font-semibold text-sm cart-item-name"></span>
        <div class="cart-item-price"></div>
        <button class="px-3 py-1 rounded-md bg-red-300 text-white cart-item-delete">x</button>
    </div>
</template>
```

Looks like the code we can easily maintain, right? Now how do we use it in the Javascript you asked?

```JS
function displayCart() {
    // Abbreviating other stuff to focus on the core topic...

    var template = document.getElementById('cart-item');

    for (let i = 0; i < cart.length; i++) {
        var cartItemTag = template.content.cloneNode(true);

        cartItemTag.querySelector("img.cart-item-image").src = cart[i].img; 
        cartItemTag.querySelector("span.cart-item-name").innerHTML = cart[i].name;
        cartItemTag.querySelector("div.cart-item-price").innerHTML = cart[i].price;
        cartItemTag.querySelector("button.cart-item-delete").onclick = function() { removeFromCart(cart[i].id) };
    }
}
```

This way, our Javascript can directly target each element inside the template and set the attributes and content respectively.

Is there any way to take this one step further? If you have any ideas, please do share.


**Wind up**

This learning is mainly for beginners when they are getting started with HTML and Javascript. As they progress, there are more options like using [templating engines](https://colorlib.com/wp/top-templating-engines-for-javascript) or going with full-fledged [JS frameworks](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks) where you manage the data and the framework takes care of the DOM updates via reactivity.

That's it. If you have some JS code generating HTML, try the template tag today and let us know how it goes. See you on the flip side.

---

_Credits: Cover Photo by <a href="https://unsplash.com/@halacious?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Hal Gatewood</a> on <a href="https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>_