Episode 17 of 21
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