Last active
May 15, 2024 06:27
-
-
Save JoshAntBrown/a05d27264a2291bb87fae9e05eefa66e to your computer and use it in GitHub Desktop.
Template Renderer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class TemplateRenderer { | |
constructor(template) { | |
this.template = template | |
} | |
render(data) { | |
const clone = document.importNode(this.template.content, true) | |
this.#processNodes(clone, data) | |
return clone | |
} | |
#processNodes(root, data) { | |
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, null, false); | |
while (walker.nextNode()) { | |
const node = walker.currentNode | |
this.#processAttributes(node, data) | |
} | |
} | |
#processAttributes(node, data) { | |
const attributes = Array.from(node.attributes) | |
for (const attr of attributes) { | |
if (attr.name.startsWith('t-')) { | |
const [type, prop] = attr.name.split(':') | |
const value = this.#evaluateExpression(attr.value, data) | |
this.#applyAttribute(node, type, prop, value) | |
node.removeAttribute(attr.name) | |
} | |
} | |
} | |
#evaluateExpression(expression, data) { | |
try { | |
const func = new Function(...Object.keys(data), `return (${expression});`) | |
return func(...Object.values(data)) | |
} catch (e) { | |
console.error(`Error evaluating expression: ${expression}`, e) | |
return null; | |
} | |
} | |
#applyAttribute(node, type, prop, value) { | |
switch (type) { | |
case 't-text': | |
node.textContent = value; | |
break; | |
case 't-attr': | |
node.setAttribute(prop, value) | |
break; | |
case 't-if': | |
if (!value) node.remove() | |
break; | |
default: | |
break; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
TemplateRenderer
On a couple of occasions, while building web apps with Hotwire and other light-weight minimal JavaScript libraries, I've needed to perform some light-weight client side rendering of a template or partial. Occasions where using a Turbo frame would have been a bit too cumbersome or complex for one reason or another.
To solve for that problem I've put together this simple TemplateRenderer class that allows for some simple template building. It's intended to be used inside a Stimulus controller, or some other similar container. Its single responsibility is to take a template element and some data model, and in turn build a clone of the template contents populated with any relevant data.
Example