← Back to all tutorials

Rendering an HTML Template

Build a practical mini-project: rendering typed data as HTML using classes and interfaces.

Rendering an HTML Template

Let's build a practical mini-project that ties together everything we've learned.

The ListTemplate Class

import { HasFormatter } from "./interfaces/HasFormatter.js";

export class ListTemplate {
    constructor(private container: HTMLUListElement) {}

    render(item: HasFormatter, heading: string, position: "start" | "end") {
        const li = document.createElement("li");

        const h4 = document.createElement("h4");
        h4.innerText = heading;
        li.append(h4);

        const p = document.createElement("p");
        p.innerText = item.format();
        li.append(p);

        if (position === "start") {
            this.container.prepend(li);
        } else {
            this.container.append(li);
        }
    }
}

Putting It All Together

import { Invoice } from "./classes/Invoice.js";
import { Payment } from "./classes/Payment.js";
import { ListTemplate } from "./classes/ListTemplate.js";
import { HasFormatter } from "./interfaces/HasFormatter.js";

const list = document.querySelector(".item-list") as HTMLUListElement;
const template = new ListTemplate(list);

const form = document.querySelector(".new-item-form") as HTMLFormElement;

form.addEventListener("submit", (e: Event) => {
    e.preventDefault();

    const type = (document.querySelector("#type") as HTMLSelectElement).value;
    const toFrom = (document.querySelector("#tofrom") as HTMLInputElement).value;
    const details = (document.querySelector("#details") as HTMLInputElement).value;
    const amount = (document.querySelector("#amount") as HTMLInputElement).valueAsNumber;

    let doc: HasFormatter;
    if (type === "invoice") {
        doc = new Invoice(toFrom, details, amount);
    } else {
        doc = new Payment(toFrom, details, amount);
    }

    template.render(doc, type, "end");
});

Key Takeaways

  • Use type casting with DOM elements for proper type support
  • Interfaces let different classes work together seamlessly
  • Literal types like "start" | "end" restrict allowed values
  • TypeScript makes DOM manipulation safer and more predictable