-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Standardize <template> variables and event handlers #2254
Comments
As it is, I can easily create 'Card's with a simple factory function in JavaScript:
|
This proposal breaks all sites that use angular default template. They will be forced to change {{ }} brackets to something else, I think. |
It doesn't breaks anything. Angular is not forced to use |
@Mevrael Sounds good to add a new special case for window.parseTemplate = (template, data) => {
var clone = document.createElement('template');
clone.innerHTML = Object.keys(data)
.reduce((acc, variable) =>
acc.replace('{{' + variable + '}}', data[variable]), template.innerHTML);
return clone.content;
}; And instead of passing an In this way, there were no need to add an special case for |
This is how I and many other engineers do now with a custom function. The problem and fact is still with a "custom" implementation. Just having such simple parseTemplate() in a Web Standards would solve many small problems and people would know what to use in that case by default and stop writing another framework. However, I may agree on that 1st argument should be a Node and not a String as all current native API works. Don't have strong opinion on There is still a question about how to handle at least simple if statements inside a template or what else we might need there by default. Since it is part of JS and we already have ES6 template strings implemented I believe it won't be too hard to implement this, something like: <template>
<alert class="alert {{ className ? className : 'alert-info' }}">
...
</alert>
</template> However I prefer real if constructions with may be custom syntax: <alert class="alert
@if(className)
{{className}}
@else
alert-info
@endif
"> |
I'm not going to respond at all to the templating language proposed. There are problems there, but they are secondary to the bigger issues. Here are a few quick, before breakfast, thoughts:
Here are a few lower-level improvements that could be made to the template element:
I'm sure there are others who have additional thoughts on improving template. I would prefer to stick to lower-level improvements at this point in time. |
Yes, DocumentFragment has only getElementById(), querySelector() and querySelectorAll(). However, why do you even need to search the template.content (DocumentFragment itself)? You should NOT change it because by that you will also modify the template itself while it should be static. Template should be cloned first and then you will get a fresh instance of Node which you will be able to iterate/search/do whatever you want. function cloneTemplate(id) {
return document.getElementById(id).content.firstElementChild.cloneNode(true);
} About your second point (reviver function). I agree that parseTemplate() at the end may receive some kind of callback (but definitely with a different name and not a "reviver"). Could you elaborate more, what do you mean by each node? Should it be each node in DocumentFragment only which usually has only one or should it be each Node with all children recursively, should it contain only element nodes and ignore text nodes? In example above I used firstElementChild and in all templates I've seen they all had only one root node - component itself, row of the table, etc. Do we even need to return all the nodes or just first element child? At the and if we will have an official template parser, wouldn't be it parsed simply as an template.innerHTML string without any nodes or you suggest to parse each node's textContent, arguments and children? There will be nothing to pass to a callback/reviver, well the parsed string could be and a custom template engine on the top of that could use it. And about the
It is not up to a one person to change the world, it is the responsibility of all of us. |
As far as I understand, this proposal has an small meaning because you can template/compile by using the current set of JavaScript and HTML features. The proof of this - there are already different template solutions in the market with different flavors. And this means, there's no need to bring template/compile/interpolate process to be part of the standard. |
I think there is a value in coming up with a standardized syntax for HTML templates just like template literals in ES6. We can let each framework & library define how each string inside I do like tagged template string model. They’re simple enough for anyone to understand but can be powerful depending on what the tagged function does. |
@rianby64 I don't think this would necessarily break Angular. This would only apply within |
Yeah, this will most likely be an opt-in feature. We can add a new attribute to enable this. e.g.
Then we may have, in scripts:
where |
There are a range of needs arounds templates, and many different ways they might be used. It'd be useful to list the needs to see how well a proposal might address them. Some of the problems I'm aware of that that frameworks and template libraries encounter:
In my experience, finding expressions within a template is the easiest problem of the above to tackle. Actual expression handling and incremental updates are the hard parts. It would be great if platform supported template syntax could scale from a case where I just want to provide some data and get back nodes with expressions evaluated (all with workable defaults) to a case where I want to provide my own expression parser/evaluator, and want to get back a data structure I can use to bridge to a vdom or incremental-dom library. The first simple use case would require some kind of "safe" or "controlled" eval that didn't have access to surrounding scopes. Something like <template id="foo"><div>{{ x }}</div></template> Simple template stamping: fooTemplate.eval({x: 42}); // <div>42</div> Template interpreting with incremental updates: const container = document.createElement('div');
container.appendChild(fooTemplate.eval(data));
const parsedTemplate = fooTemplate.parse(); // like template.content but expressions get their own nodes?
// later on data change, some made up APIs in here...
const walker = document.createTreeWalker(parsedTemplate, ...);
idom.patch(container, () => {
while (walker.nextNode()) {
const node = walker.currentNode;
if (node.nodeType = NodeType.ELEMENT_NODE) {
for (const attr of getAttributes(node)) {
const attrs = new Map();
attrs.set(attr.name, attr.hasExpression() ? evalScope(attr.expression, data) : attr.value;
}
idom.elementOpen(node.nodeName, attrs);
} else if (node.nodeType = NodeType.TEXT_NODE) {
if (node.hasExpression()) {
idom.text(evalScope(node.expression, data));
} else {
idom.text(node.textContent);
}
} else { ... }
}
}); I'm trying to show there that adding expression finding, parsing and safe eval could enable more advanced template rendering, maybe compatible with existing template systems, with much less code than now. |
I agree that adding parsing & custom processing/eval function is the key to make it work for many frameworks & libraries. I think dynamic updating is nice-to-have but not must-have for v1 of this API. For example, if that custom processing function could return an arbitrary list of node, or could get hung of an node/attribute getting instantiated, then such a mechanism could be implemented in JS. |
This is exactly the final goal of this proposal. However, implementing complicated parser at the beginning might be too much work to start from and, probably, for now we should just focus on simpler stuff which would allow just to put variables (including objects like So I would suggest for now discussing only those topics: 1. Should there be a global function 2. Should the function above return a 3. Repeating single template many times if data is an Array of Objects and not an Object. Function should return in that case a DocumentFragment of nodes where each node is a same template but with a different data - for example to generate all table rows at once. |
@rniwa for the incremental update case I'm talking about exposing the nodes so that it can be implemented in JS - not trying to bake in any incremental updating functionality into the platform (yet). In my snippet above I'm just iterating over the template nodes with expressions parsed out and calling into a library like incremental-dom to handle the updates. To me parsing and evaluating expressions is key to this area because simply finding double-brace delimited expressions is trivial - it's by far the easiest task among everything that a template system has to take care of. I implemented a template system on top Even allowing arbitrary positions for expressions requires only a tiny more logic, and this work is often done once - making the performance benefits less than something that speeds up every render. |
@justinfagnani : Sure, by “parsing”, I mean that it needs to provide some kind of context to interact with the interleaved parts. Okay, let's consider a concrete example. <template id="foo"><div class="foo {{ y }}">{{ x }} world</div></template> Here, I think we want some interface that can represent a position in DOM like Range's boundary point and let the script set/get the text out of it. Let us call this object y.value = 'bar'; // Equivalent to div.setAttribute('foo bar').
x.value = 'hello'; // Equivalent to div.textContent = 'hello world'; We might want to keep 'hello' as a separate text node for simplicity. We might want to replace the content with a list of elements: y.replace([document.createElement('span'), 'hello']); // Throws.
x.replace([document.createElement('span'), 'hello']); // Inserts span and a text node whose value is "hello" as children of div before ' world'.
x.replaceHTML('<b>hello</b>'); Inserts the result of parsing the HTML before ' world'. We also want to figure out where these things exist in the template: y.expression; // Returns y, or whatever expression that appeared with in {{ and }}.
y.attributeOwner; // Returns div.
y.attributeName; // Returns "class".
y.attributeParts; // Returns ['foo ', y]. If class="foo {{y}} {{z}}" then we'd have ['foo', y, ' ', z] instead.
x.expression; // Returns x.
x.parentNode; // Returns div.
x.nextSibling; // Returns the text node of ' world'.
x.previousSibling // Returns null. As for how to get these parts objects, we can either have a callback for each part as the engine parses it or can have a single callback for the entire thing. I'd imagine having a single callback is better for performance because going back & forth between the engine code & JS is slow. So how about something like this: foo.processor = (clonedContent, parts, params) => {
[y, x] = parts;
y.value = params.y;
x.value = params.x;
return clonedContent;
}
foo.createInstance({y: 'foo', x: 'hello'}); Supporting looping or conditional constructs that appear in many templating languages with this model requires a bit of thinking, however. Since the engine doesn't know that these constructs exist, it would probably create a single part object for each. Then how does library & framework clone these part objects so that it'll continue to function after such logical statements are evaluated? To see why. Let's say we have: <template id="list">
<ul>
{{foreach items}}
<li class={{class}} data-value={{value}}>{{label}}</li>
{{/foreach}}
</ul>
</template> list.processor = (clonedContent, parts, params) => {
for (let part of parts) {
...
if (command == 'foreach') {
for (let item of params.items) {
// BUT there are only one part for each: class, value, and label.
}
}
...
}
return clonedContent;
}
list.createInstance({items: [{class: 'baz', value: 'baz', label: 'hello world'}]}); When this came up last time (in 2011?), we thought that these logical constructions need to have nested templates as in: <template id="list">
<ul>
<template directive='foreach items'>
<li class={{class}} data-value={{value}}>{{label}}</li>
</template>
</ul>
</template> Then we can recurse whenever these constructs appear. To avoid having to traverse the cloned DOM, we can include each nested template instance in our part array so that we can do something like: list.processor = function myProcessor(clonedContent, parts, params) {
for (let part of parts) {
...
if (part instance of HTMLTemplate) {
[directive, directiveParam] = part.getAttribute('directive').split(' ');
...
if (directive == 'foreach') {
part.processor = myProcessor;
part.replace(params[directiveParam].map((item) => { return part.createInstance(item); }));
}
}
...
}
return clonedContent;
}
list.createInstance({items: [{class: 'baz', value: 'baz', label: 'hello world'}]}); If people are fined with these nested template elements, I think this is a pretty clean approach. |
I guess an alternative approach to the conditionals & loops would be letting developers create part objects manually scripts to a specific place in DOM. That would allow scripts to create these part objects as they parse objects in addition to ones we automatically create initially. |
I'm partial to nested templates, since it's been working very well so far in Polymer and my Stampino library. It also looks like it meshes very well with parts. I really like the This addresses one problem I kind of skip over as part 5) of my list above, and that's keeping track of where to insert content. vdom and incremental-dom approaches, as they have re-render-the-world semantics, can do extra work when conditionals and loops are involved - if they don't know that new nodes are being inserted to a location, they may change nodes that are after the insertion point which should instead be preserved. This is usually solved by assigning unique keys to nodes. Currently with Even though this doesn't address expression evaluation, it increases the ergonomics enough to be very useful, IMO, and I think it can be easily polyfilled :) I'm almost afraid to bring up my next thought, but bear with me here... :) I'm unsure about the stateful That is, these could simply be customized templates with a special callback: class FancyTemplate extends HTMLTemplateElement {
cloneTemplateCallback(clonedContent, parts, params) {
// ...
}
}
customElements.register('fancy-template', FancyTemplate); <template is="fancy-template"><div class="foo {{ y }}">{{ x }} world</div></template> This allows for a few niceties like lazy-loading template processors and attaching them to all templates of a type with the same machinery we have for custom elements, creating auto-stamping templates that clone themselves on attach, etc. Of course this all can be done with wrapping to. I think where it might really click with the rest of your API is with nested templates. If they are also just custom elements, they can interact with the parent template via an instance API to receive data: <template is="fancy-template">
<ul>
<template is="for-each" items="{{items}}">
<li class={{class}} data-value={{value}}>{{label}}</li>
</template>
</ul>
</template> class FancyTemplate extends HTMLTemplateElement {
cloneTemplateCallback(clonedContent, parts, params) {
for (let part of parts) {
if (part instance of HTMLTemplate) {
// attributes parts, like items="{{items}}" must have been set first for this to work
// passing params lets the directive access the outer scope
part.replace(part.createInstance(params));
} else if (part.isAttribute) {
// in this hypothetical template system we set properties by default
part.attributeOwner[part.attributeName] = params[part.expression];
} else if (part.isText) {
part.replace(params[part.expression]);
}
}
return clonedContent;
}
}
const list = new FancyTemplate();
list.createInstance({items: [{class: 'baz', value: 'baz', label: 'hello world'}]}); This example doesn't support incremental updates, but FancyTemplate.cloneTemplateCallback could stash parts and offer an I do think overall this is a pretty clean approach. |
That's an interesting approach but if a template element is specialized for a specific purpose at the time of creation, it doesn't address your concern about Perhaps it's better for Alternatively, e.g.
One drawback with this approach is that we almost always need some framework / library code to supplement this feature. But this may not be the end of the world. |
Note that I can see some library may want to dynamically change the "processor" function at runtime based on the semantics or even "directive" specified on a template if it appears inside some other library-specific constructs. It may even need to combine multiple functions to create a processor at runtime (e.g. Pipelining filters). From that perspective, passing a processor function as an argument to We could even make this argument optional and make it possible to specify the default one via attribute so that an user of a library that utiliziss this feature doesn't have to specify it when calling |
Thanks everyone for interest and repliesTo make this discussion organized and moving forward step-by-step please share your opinion by answering those questions:For now let presume that there is something called a "Template Function (TF)" which needs a use-cases 1st, API 2nd, and an implementation third. 1. What TF should exactly do?1.1. Only parse template.innerHTML/contents, everyone is ok with {{ }} syntax, what about spaces?I would stay with {{ }}, spaces doesn't matter, they could be trimmed first. 1.2. Attach event handlers (how handlers should be defined - in the same function or there should be another one, should handlers be attached during TF call or they should be attached manually later?)There are 2 options.
Example syntax with a new Totally against attaching event handlers manually later. They can be defined later (Option 2) but are still attached when a TF is called. 1.3. Have a built-in lexer and expose all the statements/variables to something like template.expressions?Not a big fan of that, however, the only use-case I see is allowing developers adding a custom control structures/syntax to a template statements, for example to register 1.4. What TF should parse itself (recognize) by default?
2. Should TF be a new global function, or a new method (where?), or a new instance (of what?). TF example names?There is no need in complicating things and I am totally against any "instances" and class syntactic sugar. A new global function 3. What TF should return? Always a Node and ignore rest child elements, or always a DocumentFragment, or it depends (on what, elaborate)?First of all in my vision if there are multiple child nodes in DocumentFragment, ignore them, template usually have only one main element child And about the return type, it depends:
4. What about a nested templates?May be leave it for now and discuss it later. |
@Mevrael hey, just wanted to poke my head in here and lend some hopefully-wisdom to the great thread you started. Which is: don't try to keep too tight a reign on the discussion here :). You've gotten that rarest of things---implementer and framework interest---in a remarkably short time. I'd encourage you to let @rniwa and @justinfagnani continue their free-form exploration instead of trying to redirect their energies with large posts full of headings and to-do lists for them to address. It's certainly up to you; just some friendly advice. |
|
|
But most importantly, we need a list of concrete use cases to evaluate each proposal. |
Since I had some time over the MLK weekend, I wrote a polyfill in ES2016 for TemplatePart: |
Why so complicated and why Apple copyright. I've created a repository for making PRs on Use-cases and Implementationhttps://github.com/Mevrael/html-template And here is a first implementation which works currently only with vars and nested vars, i.e. It adds a parse(data) method to a template prototype. Talking about the custom logic, I suppose many other methods I defined there could be also available in JS and authors, for custom logic could be able to replace any method on template prototype. Talking about the nested templates, it is NOT part of this proposal, moreover, currently |
The most of complexity comes from having to monitor DOM mutations made by other scripts. Apple copyright comes from a simple fact that it is Apple's work (since I'm an Apple employee). Also, please don't move the discussion to another Github repo. For various reasons, many of us won't be able to look at your repository or participate in discussions that happen outside WHATWG/W3C issue trackers and repositories. A template element inside a template element definitely works. In fact, this was one of the design constraints we had when we were spec'ing template elements. If anything with a template inside another template doesn't work that's a bug (either of a spec or of a browser). |
@TejasQ : Being able to use any JS expressions is totally possible with a custom template processor (just call eval). I think the only concern we had was that we wanted to prevent XSS as much as possible by design since innerHTML and friends historically had a bunch of bad XSS attack surfaces. How do you feel about making this an optional or a separate syntax. e.g. |
@EisenbergEffect : Why? Telling something shouldn't be is very unproductive in standardization processes. We need objective empirically observable use cases or some other evidence as to what is a problem. Note that If you wanted to create just a template instance and not do any data bindings, you simply omit the JS object to |
There seems to be a lot of JavaScript in this HTML. If someone disables JavaScript, are templates still supposed to work? |
Templates already don't work without JavaScript. |
Interpolating the data during clone is actually a very important part of this proposal. lit-html, which is based on a lot of the ideas here, currently has two-phase template instantiation:
This is done only because there's currently no way to customize cloning in It'll be both faster and more correct to create the initial DOM with values filled in and run all the reactions at the end of |
@snuggs I was referring to JSX's choice of Anyway, this really is the least interesting part of this discussion. The delimiter can be changed without effecting the rest of the proposal at all. |
@justinfagnani Hence why i deleted my comment in retrospect as I see your point for sure. But must have empathy for what may be the least interesting to you doesn't speak for rest of community. As long as it's been noted (multiple times) it's something people care about there is interest. 🙏 |
@rniwa If it's just syntax over create/update, then that's fine, assuming there's no negative effect to not passing a data object. It's important that a program be able to instantiate a template in one place, and then pass the instance to some other part of the program to actually supply the data. We made the mistake of mixing the create and bind responsibilities early on during the alpha phase of Aurelia and it caused us a lot of problems in the context of the larger component model. So, we had to make a breaking change to split them apart. |
@EisenbergEffect I remember that... 💜 |
@EisenbergEffect yeah, it seems like this is an important feature for libraries & frameworks. The polymer team had a proposal which fixes this problem. My only concern is that the API exposed to the end user should be simple but I'm sure we can come up with an API that satisfies both concerns. |
Apologize in advance for losing track of context. However this conversation has gotten quite detailed. Can you please refresh me with a comment link perhaps to the two "concerns"? Thanks in advance 🙏 |
Two concerns are:
|
Opened a bikeshed ticket (#4219) to avoid polluting this thread any further 😄. |
After reading the whole discussion, I would like to propose a different approach - one that dodges the issues with delimiter choice / preferences, does not suffer from HTML parser issues (as much), does not have to deal with what kind of expressions should be allowed within the dynamic parts, nor requires us to decide whether to include extra syntax for features such as conditions, loops and template composition. The example below roughly demonstrates what I have in mind, demonstating data binding, looping, event listeners, element references, composing templates and updates: const appTemplate = document.createDynamicTemplate(`
<div class="comments">
<ul>
`, `
</ul>
</div>
<form `, `>
<textarea name="comment" `, `></textarea>
<button type="submit">submit comment</button>
</form>
`)
const commentTemplate = document.createDynamicTemplate(`
<li class="`, `">
<p>Author: `, `</p>
<p>`, `</p>
</li>
`)
const appInstance = appTemplate.instantiate(
(instance, comments) => {
instance.parts[0].replaceWith(...comments.map(
comment => commentTemplate.instantiate(
commentTemplateProcessor,
comment,
),
))
instance.parts[1].element.addEventListener('submit', (event) => {
event.preventDefault()
const text = instance.parts[2].element.value
// both instance and appInstance can be used here
appInstance.parts[0].nodes.appendNode(commentTemplate.instantiate(
commentTemplateProcessor,
{
text,
author: 'you',
},
))
})
},
await apiClient.fetchComments(),
)
function commentTemplateProcessor(instance, comment) {
if (comment.author === 'you') {
instance.parts[0].value = '--authored-by-current-user'
}
instance.parts[1].replaceWith(comment.author)
instance.parts[2].replaceWith(comment.text)
}
document.body.appendChild(appInstance) In this proposal I am deliberately limiting the number of parts controlling a single attribute or comment value to 1, just to keep things simpler. I am afraid that allowing multiple parts in an attribute value would lead to confusing behavior for consumers of the parts API ( My proposal, however, does allow multiple Node parts mixed with "static" Nodes on the same DOM hierarchy level, including Node parts at the root level of the template. Note that the instantiated template keeps track of its parts and child nodes and exposes them to allow easier updates. The instantiated template extends the The proposed API is indeed more low-level, but that would IMHO enable most (if not all) current template engines/libraries to utilize it in their implementations, including React, Vue.js, Polymer or HyperHTML. This could reduce the complexity of their own code and (hopefully) improve their performance. The obvious down side is worse developer ergonomics, however, since everyone has different preferences when it comes to what the ergonomic API should look like, and these preferences even change with time, I suggest leaving that to the libraries that would be built upon this. A more detailed, more formal description of the proposed API, a partial polyfill and a few demos are available here: https://github.com/jurca/dynamic-template. |
This can be alternated with |
@jurca Your suggestion can be easily implemented in JavaScript using template tag functions. I'm guessing that's why people downvoted it. Many libraries already do this, f.e. with syntax like const name = "Nambaru"
const div = html`
<div>
<span>Hello ${name}!</span>
</div>
`
document.body.append(div) and the To this effect, there's is not much new in your suggestion, except proposing what any of the existing libraries could make their API be like. The proposal being discussed is about adding the feature to directly to HTML DOM itself. In theory perhaps this can be expanded so that even a user can use templates (importing data with |
At the moment, there are plenty of libraries with very fast templating that a built-in solution would need to outperform. See the well-known js-framework-benchmark by @krausest: https://krausest.github.io/js-framework-benchmark/current.html Will a built-in solution be able to bring better performance to even the fastest of those libraries? My gut feeling is that, for the libraries that use "fine-grained updated" (just like the above template parts proposal does), the answer may be yes, if we ignore the The current fastest way to stamp templates is to make a Based on this, a library will want to be able to stamp templates out multiple time over and over, and if they have to create a new Will Basically if the new approach is not faster than current, I think lib authors will be hesitant to adopt it. End users won't care much, they just keep writing what they already write. |
I disagree with the placeholder. I'd use the same as string templates I disagree with the |
@trusktr You are correct. I assumed - wrongly :) - that this might be the easier way for everyone to agree on something minimalistic, that can be used by the current and possible future solutions. With hindsight, I can see that I approached the problem from the wrong angle. Also, I admin that the web probably doesn't need another hard-to-use needs-to-be-wrapped-in-a-library API. My apologies to everyone for that needless post, I was just trying to help. @carnoxen @brunoais While it may seem convenient to use the same templating syntax that we already use for strings, I'm afraid that this will lead to confusion for end-users writing their HTML templates in ES6 template string literals (which are the only string literals that support multi-line strings without escaping). Choosing a different syntax will enable users to template "semi-static" parts in the string literal and dynamic parts using the template API, and won't lead to the aforementioned confusion. However, I agree that dropping the |
I think we have to resolve two main problems.
There is actually a problem with how is parsed the template element content. (see last part of https://github.com/domenic/template-parts#parser-problems) Why type attribute ? With it, each framework is free to continue to use their own template engines. So the second point is respected ("Don't break what it already works"). But for the first point, we may choose what kind of template engine should be natively available in html, in order to provide a standardization, a default prefered template, without impose it and break existing solutions.
I've already posted a proposition (in a duplicate ticket, oops, sorry) for the handlebars template engine, whish seems (to me) complete enough, simple enough, and consensual enough to be choosen (see #9004). Note that since handlebars is based on mustach and is compatible with it, choose handlebars is like choosing mustach more few basics features like helpers in addition. From the javascript side, we should have a standardize way to feed variables assignements for the template and to render it. I'm not sure it will be required to provide more normalisation constraints here, regarding helpers adding for example, because each template engine have their own logic. Note about user agents implementations : handlebars is already ported in a lot of various languages (JS, RUST, C, PHP, PYTHON, JAVA, RUBY, OBJECTIVE C, SCALA, .NET, and probably others). Which makes it a good candidate (language agnostic). |
When I said
This does not mean that User Agent have to embed the acutal library in JS format. Browsers can be free to use the C compiled implementation for the lower level, but following how API functions are already provided by the existing JS version for the upper level, just to not reinvent the wheel. |
The last mentionned issue (#9014) aims to provide a way to indirectly resolve the parser problem from the server side. |
If this new feature is adopted, browsers that do not implement it will encounter the parser problem described at the end of this document : https://github.com/domenic/template-parts#parser-problems |
Proposal by Apple - https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Template-Instantiation.md
Proposal by Google - https://github.com/domenic/template-parts
This is a proposal on standardizing
<template>
parser which would allow developers:Current stage: Open Discussion about the HTML syntax and JS API
Why?
Templates finally standardized the way of making re-usable parts of HTML, templates for widgets/components, however, they are still weak and one of the most general use cases in templates is to put data into them which, currently, is not possible without using a 3rd party library (template engine) or a custom implementation.
This brings:
What is needed to be discussed and standardized?
<template>
.<template>
.<template>
1. Variables inside a
<template>
I would +1 the most popular solution used across many template engines in many languages - variable name should be put inside a {{ }}. To make life even easier and faster it could be implemented as a simple string.replace. We may force developers to write a variable name without a spaces, i.e. {{ var }} will be invalid and {{var}} will work.
2. Attaching event handlers to a
<template>
elementsI would propose here new
handler="method"
attribute which would receive an Node when called.Example HTML
Example JavaScript
In JS I would suggest just adding new function
because current syntax and manual clone/importNode is ridiculous. We already have functions parseInt, parseFloat, etc.
Currently I have no opinion on statements, may be, we could allow only simple inline statements like in ES6 template strings.
The text was updated successfully, but these errors were encountered: