This gist was updated based on the discussion here : https://groups.google.com/forum/?fromgroups=#!topic/yui-contrib/cUpVvtoUBa8
With the ability to precompile templates into javascript and the abtraction layer provided by Y.Template to normalize the api to render those templates, we got one step closer to create applications that can be template language agnostic.
The premise here is to create a YUI Application that references templates by name and call for render when needed without having to know what engine to use, or what file generated the compiled template, or what api should be used for a particular template.
In order to facilitate this, we should have a centralized registration mechanism used by the application to register any template that is provisioned, in which case we can decouple the provisioning process from the actual rendering process.
The initial proposal is to utilize Y.Template
as the central hub for all those templates, and doing so by introducing three new static methods, register
, unregister
and render
.
To register
a compiled template:
var revivedTemplate = Y.Template.register('templateName', template);
note: the revivedTemplate
is probably the same as argument template
, but just a guarantee that the function complies with the revive
API in Y.Template
.
note: the register method override any existing template with the same name. this will help with live updates in development mode.
To unregister
a template by name:
var wasRegisteredBool = Y.Template.unregister('templateName');
which returns a boolean in case you want to know if the template was previously registered.
To render
a registered template:
var html = Y.Template.render('templateName', data);
var revivedTemplate = Y.Template.register('name', function (data) {
return 'some string';
});
var someString = revivedTemplate({foo: 'foo'});
The means the function passed to register()
should be a function which conforms to the above contract. It is up to the thing which precompiles it to encapsulate or close-over any underly template engine specifics.
var someString = Y.Template.render('name', {foo: 'foo'});
var wasRegisteredBool = Y.Template.unregister('name');
A good example of this will be a nodejs application that uses YUI on the server side to precompile templates generating YUI Modules that can be use
on-demand or required
by our business logic, where those modules can do the provision of templates into the internal register, which guarantees that our business logic can render them. Some code:
Pre-compiled template into a module:
YUI.add('foo', function (Y, NAME) {
var compiled = function (data) {
/* compiled template */
return '<html fragment>';
};
Y.Template.register('foo', compiled);
}, '', {requires: ['template-base']});
Where the business logic can require foo
to guarantee the provision:
YUI.add('bar', function (Y, NAME) {
var html = Y.Template.render('foo', {
tagline: 'bar is now template language agnostic'
});
}, '', {requires: ['foo']});
- The internal cache mechanism should not be expensive
Y.Template._cache = {};
as the cache mechanism should be just fine.- Throwing when unregistered template is invoked
Y.Template.render
vsY.Template.prototype.render
might be confused, we need to clearly state this in the docs.- The nature of the
render
method is syncrounous, hence any register template should be syncronous.
@caridy:
Then maybe this shouldn't be part of Y.Template, since the implication of it being there is that it will work with any Y.Template-wrapped engine. We can't expect all compiled template functions, regardless of engine, to have the exact same arguments and behavior.
Y.Template exists to provide a generic abstraction over template engines with different APIs.
This proposal proposes new APIs and functionality. That's solid infrastructure, not guidelines. :)
I'm open to other solutions, but I do think it's important that engine abstractions be supported for registered templates. We can't just blindly assume that all registered template functions follow the
function (data) { } => html
pattern.Not true. You only need to load Y.Template.Micro if you aren't going to specify another engine.
This requires the calling code to know what type of template it's rendering, and means the template engine is explicitly linked to the component that uses those templates.
One of the great things about Y.Template right now is that even if I write a component that uses Template.Micro, you can override the component's default templates with your own custom templates using Handlebars or anything else, and you don't have to modify the component itself to call them differently. They just work.
A protected property (
_cache
) is fine, because it indicates that people shouldn't mess with this thing unless they're willing to accept the consequences. We absolutely should not make this a public property, though. It's internal state, not a public API.