Re:Templating in HTML
by lenkite on Wednesday October 05, 2022 @03:27AM
(#33092353)
I wish HTML and not just JS had supported for consuming templates.
That is I wish we could do variants of:
With substitution variables/text, this feature could be amazing.
[ Parent
| on HN ]
> With substitution variables/text, this feature could be amazing.
At which point, are you just re-creating JavaScript?
Not quite, I think he is taking about a more declarative approach compared to that offered by vanilla JS.
But works with disabled JS.
Here's what I got:
const $template = function(template) {
// make copy of template content
const root = template.content.cloneNode(true);
// create proxy object for accessing named nodes and root
const obj = {
get $root() {
// after template root is called, remove this getter function
delete obj.$root;
// return root only once
return(root);
}
};
// find all named template nodes and add to proxy object
for (const node of root.querySelectorAll('[data-tmpl-name]'))
obj[node.dataset.tmplName] = node;
// otherwise create template node content wrapped in proxy which
// makes attempts to overwrite properties an error.
return(new Proxy(obj, {
set: () => { throw (new Error(`Attempt to overwrite a template node!`)); }
}));
}
You can use it with something like: <template id="some_id">
<div>
<h3 data-tmpl-name="header"></h3>
<h5 data-tmpl-name="title"></h5>
</div>
<p data-tmpl-name="info"></p>
</template>
And then just: function of_some_sort() {
const t = $template(document.getElementById('some_id'));
t.header.innerHTML = 'The Header';
t.title.innerHTML = 'The title';
t.info.innerHTML = 'More stuff.';
document.body.append(t.$root);
}
This is was the first version I made. It's not hard to get from here
to a version that can fill the template with a data object for you. In
my most recent version, you could do: function of_another_sort() {
document.body.append($template(document.getElementById('some_id'), {
header: 'The Header',
title: ['first title', 'second title'],
info: (elem) => {
elem.setAttribute('functions', 'work');
elem.innerHTML = 'and receive the internal element itself.';
}
}));
}
Arrays duplicate the internal element and make copies of it, objects
recurse into the element building a 'key.path.name' while looking for
data-tmpl-name to replace. Functions get a copy of the element for
more than just innerText/innerHTML replacement. A null or false value
eliminates the internal element, and a true value passes it through
unchanged.If you've ever used the old ruby library Amrita, it's basically that, but for HTML Template elements. You can easily do all this in about 100 lines of JS.
I just tested out how to use template with slots, and it was as you said quite simple.
Made a simple gist: https://gist.github.com/vidaj/b27f1140a8ae711c7df2372c4b5cfe... It supports using templates as slot content and updating only the slots you want. Add in some event listeners, and you got basic binding support.