Closed ghost closed 2 years ago
The proposed syntax:
base.mustache
{{#items}}
<p>{{>.}}</p>
{{^items}}
and
base.mustache
{{@items}}
Assume there is a key named 'partial' and then looks up that partial. The idea of dynamic partials is great, but I don't know about assuming a certain key to be present is the most developer friendly approach and the easiest to understand quickly. It could instead by {{>.partialName}} which, when the lookup for the literal key '.partialName' fails, it resolves .partialName to 'text' and looks that up.
It's clearly valuable, but I don't think it fits in the spec for 2.0
See my response here: https://github.com/janl/mustache.js/pull/242#issuecomment-8645571
As for it not fitting the 2.0 spec, there is currently no way to render partials dynamically which I see as a significant drawback. This is fine for smaller projects as you just add a boolean to each object in a collection such as is_text
or is_image
and have conditions in the template:
View
{
items: [
{ type: 'image', url: 'Some URL', is_image: true },
{ type: 'text', content: 'Some text', is_text: true }
]
}
{{#items}}
{{#is_text}}
<p>{{content}}</p>
{{/is_text}}
{{#is_image}}
<p><img src="{{url}}"/></p>
{{/is_image?}}
{{/items}}
But... as soon as this goes above a couple of types, things get hard to manage. The whole premise of Mustache is to keep logic out of the template and this reads to me as a bunch of if
statements.
Wouldn't it be nicer to be able to do:
base.mustache
{{@items}}
text.mustache
<p>{{content}}</p>
image.mustache
<p><img src="{{url}}"/></p>
So much cleaner, don't you think?
Sorry to labour my point, but I'm using this in production and it's changed my life :)
@thelucid As usual, when one's code contains too many if
, it means that you need a to inject a little object-oriented design. Let's replace your is_text
, is_image
"queriable" attributes by some "performing" attributes, and use Mustache lambdas:
{
items: [
{ url: 'Some URL', html: function() { return '<p><img src="{{url}}"/></p>'; } },
{ content: 'Some text', html: function() { return '<p>{{content}}</p>'; } }
]
}
base.mustache:
{{#items}}
<p>{{{html}}}<p>
{{/items}}
And, if you absolutely want to use partials:
{
items: [
{ url: 'Some URL', html: function() { return '{{>image}}'; } },
{ content: 'Some text', html: function() { return '{{>text}}'; } },
]
}
base.mustache
{{#items}}
{{{html}}}
{{/items}}
text.mustache
<p>{{content}}</p>
image.mustache
<p><img src="{{url}}"/></p>
And voilà, no need for a spec update!
@groue Ew, I'm sorry but this is exactly why the functionality is needed. Returning chunks of html from the view is in no way a good solution to the problem... I would hope I'm not alone on this.
This is in fact a perfect illustration as to why we need a clean solution to this problem, if hacks like @groue is suggesting are being suggested then something is fundamentally wrong.
@thelucid You call it a "hack" because you see data
as a model model object, not as a view model. I can understand you: Mustache has always been ambiguous on that subject: advocating simplicity, saying "just give me your model objects, I'll render them", while defending itself against missing features with arguments like "just add the missing keys to your view model, you shouldn't have provided a model in the first place anyway".
Mustache spec issues history is full on this kind of situations, if you read them carefully.
So, in a way, I gave an answer that is typical of the "Mustache 1" spirit. Be free to suggest improvements for Mustache 2. But dont' call "hacks" ways to use Mustache that you just don't happen to like.
@groue I'm sorry, I just don't see that returning a chunk of html from a view object (be it a view model or a data model) is a maintainable solution. Where do you draw the line, you may as well bypass Mustache completely and just interpolate strings.
I would much rather do:
base.mustache
{{@items}}
text.mustache
<p>{{content}}</p>
image.mustache
<p><img src="{{url}}"/></p>
@thelucid Have you read my message? Check after the "And, if you absolutely want to use partials:" sentence.
@groue Yes, I have read the message and there are a few problems with the suggested partial solution:
{{{html}}}
approach.Injection example:
{
items: [
{ url: 'Some URL', html: function() { return '{{>image}}'; } },
{ content: 'Some text', html: function() { return '{{>text}}'; } },
{ html: '<script>alert("I am hijacking your page")</script>' }
]
}
It's ugly but that's just my opinion.
As much as the is_text
and type
attributes, and more OO.
It's not DRY
Single interface + Liskov substitution principle is no DRY for you? Gosh, I can't see how more DRY it could be.
It's unmaintainable, i.e you will have to add a function for every new partial.
Your solution must keep synced the type value and the partial name, which is just the same chore.
It's open to injection attacks since you are using the {{{html}}} approach.
Is it? open a new issue, and ask for a removal of the triple mustache.
Listen: I won't defend my proposal more than necessary. Actually, I'm quite sure you didn't know about the lambda before I introduced them to you. Think more about the tool, make sure you know every tiny details: Mustache is more rich that it looks. Maybe you'll find a solution that conforms to your standards with the spec as it is.
I'm at a loss as to why you're against a clean solution to dynamic partials.
As much as the is_text and type attributes, and more OO.
That is exactly why I am suggesting such a feature, it is dry and concise.
Single interface + Liskov substitution principle is no DRY for you? Gosh, I can't see how more DRY it could be.
You are still duplicating a function which is not DRY.
Your solution must keep synced the type value and the partial name, which is just the same chore.
Yes, but you are just specifying the partial to render, not a function that actually renders a chunk of html.
Is it? open a new issue, and ask for a removal of the triple mustache.
The triple mustache doesn't escape the value by design, that's what it's for and how it works. So yes, your example is open to injection attacks... try it if you don't believe me:
View
{
html: '<script>alert("See, I have control");</script>'
}
Template
{{{html}}}
I did know about lambdas before you mentioned them (that's a little patronising, especially given your lack of understanding when it comes to the triple mustache), I just don't see them as a good fit for this particular problem.
We'll just have to agree to disagree on this one.
Maybe you'll find a solution that conforms to your standards with the spec as it is.
There is currently no way to render dynamic partials other than the suggestions we have already exhausted here, hence this ticket.
I'm not against your solution. I just wanted to make sure everybody knows that there are already existing solutions. Usually, people ask for a feature because they don't know their tool enough. Sorry if I have patronized.
About the triple mustache: they allow injection in all situations, not only in the one we are talking about here. What I meant was that the topic of injection should hence not pollute this topic, and that you can ask for the removal of the triple mustache in some other issue.
I think @groue has a great point. This is already possible, therefore it's best not to add a feature for it.
I vote no.
It's possible to drive a nail into a block of wood with a mallet but it's not necessarily the best tool for the job.
I think letting{{>string}}
first lookup the partial named 'string' - and then fallback to looking up the value of the string would certainly be acceptable. This would work perfectly without changing anything, only at a point of failure does it kick in.
And with @bobthecow's suggestion of moar dot notation hotness, you could do{{>.string}}
Yes, that's not too bad, what about the {{@collection}} shorthand?
The only potential problem with that solution is that it's a little ambiguous i.e. the same syntax does two different things. Having a separate syntax makes it easier to see what is going on.
That should be explicit, if that's what you want. Otherwise you're opening yourself up for exploits. Maybe use a "variable dereferencing" type token? {{> *string }}
What about using the @
symbol for everything related to dynamic partials e.g.
{{#items}}
{{>@partial}}
{{/items}}
or shorthand that assumes a partial
key:
{{@items}}
I would personally prefer it being implicit, going with a convention whereby a partial
key is always assumed when using dynamic partials i.e.
{{#items}}
{{@}}
{{/items}}
and shorthand:
{{@items}}
The @
symbol then means "render an object or collection of objects using their partial
keys". Of course, the key doesn't necessarily have to be partial
, perhaps >
would be a better fit to denote a partial? ...hmm, maybe not, partial
does what it says on the tin.
Has anyone tried a few examples using my patch to mustache.js
? The {{@collection}}
shorthand really is a joy to use, maybe that's all that's needed and we abandon the longhand.
Not a fan of using@
:(
@bobthecow Could you give an example of being exploited?
We could also use another interesting syntax:
{{> {{string}} }}
It seems the only way we dodge ambiguity is by having a special char or marker that means lookup the value of this string not the name 'string'
%
? Looks a bit like repeating partials if you tilt your head to the left :) {{%items}}
.
In response to the dereferenceing thing, &
is commonly used for this in programming languages e.g. {{> &thing}}
.
{{> {{string}} }}
is kinda interesting because it presents the idea that anything can be dynamic lookup. *
could be just as universal.
Essentially we're talking about the same thing - some symbol to 'dereference' the variable. I really like @bobthecow's*
because that's exactly what it means in any non-garbage collected language. (C, C++, etc..)
Not keen on the taches in taches thing, wouldn't that choke the parser?
I'm currently leaning toward:
{{#items}}
{{> &partial}}
{{/items}}
with a shortcut of:
{{%items}}
or
{{@items}}
The{{> {{string}} }}
syntax would require a more intelligent parser... compiling it would also be a bit more complicated too, I'm not very big on it.
I wonder how a lambda/filter/helper could assist you with a shorthand version...
*
?I'm not against using *
although prefer &
as it's more Rubyish and reminds me of things.map(&:name)
which does exactly what we want.
With regards the shorthand version, in practice this is more useful than the longhand. In fact, I'm using this setup in a couple of projects and have not actually had a need for the longhand version over the shorthand. The resulting templates are super clean and concice.
Let's say you have a page with main content and sub content, and each contains a collection of objects, this becomes (using @
here but could use %
instead):
<html>
<body>
<div class="main">
{{@main}}
</div>
<div class="sub">
{{@sub}}
</div>
</body>
</html>
I would be more interested in the shorthand making it in over the longhand, be it {{%items}}
or {{@items}}
. It's a super simple patch, only requiring a few lines of code in return for powerful dynamic partial functionality.
@thelucid : are you proposing to reserve a special key partial
for your shorthand notation?
Not to necessarily reserve it but the convention would be that when rendering a collection of partials, use the partial
key. Have a play with my fork of mustache.js
, you'll see how nice it is to use, it just works.
I do quite like the {{> *partial}}
or ideally {{> &partial}}
notation too, however in practice the shorthand gets far more use.
@thelucid : Don't play on words: you are indeed "blessing" the partial
key it for some special purpose of your own convenience.
Of course, you are feeling it is a bad idea. And you are right: it's a big threat on compatibility. Each time a special key is added to the spec, one has to bump the Mustache version by a major increment (Mustache 2.0, 3.0, etc.) since it could break existng code.
You can give up this idea right away - it will never enter the spec.
I'm not playing on words, this functionality is backwards compatible, if you took the time to think about it or try out the patch before mouthing off you would see that. I'm just throwing some ideas out there that I have found to be hugely beneficial in my own projects and that I thought others could benefit from.
This ticket has thrown up some interesting discussion around the {{> *partial}}
/{{> &partial}}
syntax so I believe it to have been worthwhile. Far more worthwhile than your suggestion of returning a chunk of HTML.
Your negativity is getting on my nerves and don't tell me what or what not to do. Go find another ticket to troll.
p.s. what makes you think that I think it's a bad idea?
It is not backward compatible, since a key has become blessed. Code written before the change may use this key. If the user updates the Mustache engine, the rendering will be different.
You will tell me: "this will not happen, since the user has to explicitely opt-in for the shorthand notation. Hence the change is backward compatible, and you are a bad troll".
Sure. Rigorously, you are right. But sooner or later we'll have many smart guys that will bless more punctuation signs and more keys, for their own convenience, and compatiblity will blow up.
Second reason why key blessing is bad idea: user's data is user's data. Don't mess with it, for your own convenience.
What's with all this "key blessing" nonsense. Existing templates will work just fine, you can use the partial
key as much as your heart desires and the shorthand just introduces a convention whereby a partial
key is used to specify the partial for each item (how often have you actually had a partial
key in a view object? ...I would guess never). It's not for my own convenience specifically, it's to allow Mustache users to render a collection of items using specified partials, a pretty common scenario.
Rails uses conventions all the time and that's what makes it such a powerful framework, are you saying that Rails controllers shouldn't assume a show
or index
method just incase someone wants to use it for something else?
If you are so against convention, how about something like:
View
{
items: [
{ partial: 'image', url: 'Some URL' },
{ partial: 'text', content: 'Some text' }
]
}
Template
{{items >*partial}}
or
{{items >&partial}}
Not too bad, but also not too pretty, that's what happens when you don't have conventions.
This does mean that you could also render a collection with an explicit partial too which is quite interesting:
This:
{{#items}}
{{>my_partial}}
{{/items}}
Could be declared as:
{{items >my_partial}}
how often have you actually had a partial key in a view object? ...I would guess never
This is typically the behavior I try to avoid for myself : thinking for other people, and believing that my case is the case of everybody. Should a single people, a single user (we are doing user interface here) use a blessed key without knowing it is blessed, his rendering will fail in a confusing and non trivial way, leading to a painful debugging session. This would be bad for that user, and bad for Mustache. Again, for your own convenience - I'll repeat as often as needed that Mustache 1 already provides the feature everybody here pretend is missing.
Your comparison with Rails is interesting, but I have nothing against conventions. I'm a very happy Rails user myself. I would have used the arguments however, should you have been DHH in person. Namely: don't mess with user data because you don't own it, and don't bless keys for backward compatibility's sake.
A new proposal:
What about changing the regular partial syntax from {{> foo }}
to {{> "foo" }}
, so that {{> foo }}
now means "render the partial whose name is stored at the key foo
", just like {{ foo }}
means "render the value whose name is stored at the key foo
" ?
It would be much more consistant than Mustache 1, and make useless the need for a dereferencing syntax. What do you all you think?
Did you read my alternate suggestion that addresses all your concerns? Not as clean but that's what happens when you don't have conventions.
I'm not trying to think for other people, just suggesting a clean solution to dynamic partials, that's all... not some big conspiracy.
I'll repeat as often as needed that Mustache 1 already provides the feature everybody here pretend is missing.
I'll repeat as often as needed that returning a chunk of HTML is not a proper solution to dynamic partials.
What about changing the regular partial syntax from {{> foo }} to {{> "foo" }}
From someone who's worried about breaking compatability, now this does break comparability.
Does anyone else have a view on the discussion so far as I'm losing the will to live?
@thelucid : you did not understand my concern about compatibility. Here we are talking about Mustache 2, so we can break stuff if we want. Not ideal, but we can. However, the introduction of a blessed key would provide a hazardous pattern: each enw feature that would "need" a new blessed key would have to bump Mustache major version. Even tiny features that would only deserve a minor bump. That is the only concern with blessed keys. And if there is something in these sentences that you do not agree with, I'll be happy explaining until you understand that blessed keys are plain wrong, however nice they look at first sight. Nothing personal here : keep you will to live.
@groue in regards to{{> "foo" }}
, if we said that{{> foo }}
, upon failure, would fallback to looking up the partial by the name of this key ('foo') instead of searching the it's value as a string this would work. Interestingly, it's the flip of a dereference operator.
I have to agree with groue on the shorthand/special key, it's just not getting into the spec.
Did you read my alternate suggestion that addresses all your concerns? Not as clean but that's what happens when you don't have conventions.
You are focusing on the rendering of dynamic partials for collections. You are trying here to solve two problems in the same time. What about focusing on dynamic partials first, and then see how it fits with collections?
@groue I understand what you are saying but they are only "blessed" (as you call it) when you explicitly use a feature that makes clear it's intent in the documentation.
What about the {{>static_partial}}
, {{>*dynamic_partial}}
and {{items >static_partial}}
and {{items >*dynamic_partial}}
notations? Doesn't this address your concerns?
I personally don't see the need to be quite so explicit but it addresses your concerns.
in regards to{{> "foo" }}, if we said that{{> foo }}, upon failure, would fallback to looking up the partial by the name of this key ('foo') instead of searching the it's value as a string this would work
@devinrhode2 the problem would be that your feature would be backed on a failure, that is to say a condition that may be unexpected by the programmer. Expect hours of painful debugging, here, again.
On the opposite, {{> "foo" }}
, {{> foo }}
and {{ foo }}
all say a single thing at one time, and are very consistent. One could say that partial tags used to contain a "template name". Now they contain an "expression" just like variable and section tags: {{> partial }}
, {{> item.partial }}
, {{> first(items).partial }}
(using parentheses-based filters).
Of course, a consequence of {{> "foo" }}
vs the dereferencing {{> foo }}
would be that {{ "foo" }}
would have to render "foo". This is the introduction of literals in Mustache. I expect some people will not like that. Still, this is an elegant solution to the dynamic partial "problem" (admitting there is one in the first place).
@devinrhode2 Fair enough on the shorthand, at least we're in agreement that there needs to be a better way to render dynamic partial than returning a chunk or html.
I'm not keen on one syntax having two possible outcomes i.e. falling back to a key if a partial is not matched. In which case, I vote for:
Dynamic partials:
{{#items}}
{{>*partial}}
{{/items}}
I guess you're not taken by the alternative to {{%items}}
or {{@items}}
?
{{items >*partial}}
...I was just trying to come up with a way of not always having to write the open and closing tags as it's quite a common pattern.
What about the
{{>static_partial}}
,{{>*dynamic_partial}}
and{{items >static_partial}}
and{{items >*dynamic_partial}}
notations? Doesn't this address your concerns?
Yes. However, as an implementor, I would not be happy implementing the shortcut notation. It's there only to fulfill a very specific use case, and I would feel I spend time for a very little user benefit. As soon as you want to render a collection with some decoration, the short syntax becomes useless, leaving everybody using the "long" syntax. Also, the "long" syntax is {{#items}}{{> ...}}{{/items}}
... Is it really so long, frankly?
@thelucid, as a Mustache implementor, what I've seen is that users are amazingly various, surprising, and rich. They always have needs I would have never imagined. And it's a joy when you see that all you have to do is to guide the users in your library, so that they can use it in order to accomplish their goal. I'm really against feature bloat. Because it never stops. Some guy will want a shortcut for this. This guy will want a shortcut for that. What they need is a library that can take many shapes, that can host many patterns, that can fit the user's needs, a library that does not need an update when some guy has some crazy idea. That's why I sound so conservative.
@groue Fair enough, I guess I've been in the Rails community for too long where creating shorter, more concise and convenient ways of doing things is ingrained (I created "sexy validations" in ActiveModel core for example).
Over time, the partial syntax in Rails went from:
<%= render :partial => "item", :locals => { :item => @item } %>
to...
<%= render :partial => "item", :item => @item %>
to...
<%= render :partial => @item %>
to...
<%= render @item %>
And collections of partials from:
<%= render :partial => "item", :collection => @items %>
to...
<%= render :partial => @items %>
to...
<%= render @items %>
If we had an inflector in Mustache we could do:
{{>items}}
...and it would automatically look for an item
partial but I guess an inflector is going too far and still wouldn't account for dynamic partials.
@thelucid I'm a happy Rails user, and also an Objective-C developer. Both environments focus on expressivity, with a concise variant on the Rails side, and a verbose variant on the Obj-C side. Now this can explain our "culture clash" :)
If I sum up, we have two subjects:
A: The syntax for static and dynamic partials, with two options so far:
{{> static }}
and {{> &dynamic }}
or {{> *dynamic }}
{{> "static" }}
and {{> dynamic }}
The first introduces a special syntax for "dereferencing". The second has no need for "dereferencing" concept, is more consistent with variable and section, but introduces literals.
B: the questionable need for a collection shortcut, and whether it would be a good idea to "bless" some keys in order to help shortcuts.
My take on the subject is already known. Special keys are a big potential threat on backward compatibility, for a debatable benefit: the "long" version works, for Christ's sake. BTW, what are the special methods that Rails read in order to implement <%= render @item %>
and <%= render @items %>
?
@groue Rails uses the class name which we obviously don't have and makes use of an inflector to get the singular which we also don't have.
the "long" version works, for Christ's sake
True, I'm just not a fan of the "If it ain't broke don't fix it" mentality, and instead prefer progress. As I said, you can drive a nail into a block of wood with a mallet but a hammer would probably be your best bet.
My vote on subject "A" is most definitely option 1 as I really don't like the idea of introducing literals.
We're obviously not going to agree on a shorthand ("B") which is a shame as I'm using (and will continue to use a variant of) {{@items}}
in a couple of projects as it cleans up templates no end.
I guess the real way forward, after we have agreed on the dynamic partial syntax is to introduce a way for developers to register app specific functionality, so that crazy people like me and those trying out new ideas can do:
Mustache.Renderer.register('@', function(name, context, options) {
// My custom functionality
return 'the output';
});
This could also cleanup the internals.
See: https://github.com/janl/mustache.js/pull/242#issuecomment-7613180
Rails uses the class name which we obviously don't have and makes use of an inflector to get the singular which we also don't have.
Yes indeed. No magic special blessed key is needed. And that's why it's OK.
The only "blessed" name I can think of right now in Rails is the to_param
method. Convenient, but not quite elegant since suddenly models have their word in the URLs. Anyway, it's convenient, let's face it. And in this case, yes, it's quite unlikely that a user would define his own to_param
method for some other purpose. And should he, anyway, he would be wrong, since he committed into Rails: by using Rails in the first place, a framework, he has a lot of documentation to read, in order to design classes that fit in the framework. As a side effect, all classes designed for Rails are locked in, now. I don't quite remember this time, but porting from Rails from/to Merb wasn't very easy, I guess.
But Mustache is not a framework. It's a dumb template engine. A mere tool.
My vote on subject "A" is most definitely option 1 as I really don't like the idea of introducing literals.
I usually try to tell you why I don't like some ideas. It would be nice of you to do the same.
Mustache.Renderer.register('@...
It would sure be nice to send out all this painful Mustache to the user. Not an easy task, though, especially when you want to keep intact the hosting language agnosticism of Mustache. Of course, you may want as many Mustaches as users, and ruin the cohesion of today's Mustache landscape.
You know, my GRMustache is quite an old library now, it may be two years old. Its API has continuously evolved, so did its feature set. But no features were added. No. instead I have increased the expressiveness of the library. So that users can extend, with their user-land code, the basic Mustache engine. Want to render 0-based indexes? 1-based indexes? Want to render something every odd elements? Want to format numbers, dates? Need a default values for missing ones? Need to debug your templates? Need to localize portions of your templates? Localization with parameters, so that the template renders "Arthur and Barbara are friends" or "Arthur et Barbara sont amis" ? Check. Done. All of this is based on a genuine Mustache 1 core, and a few carefully designed hooks so that the user injects the code Mustache 1 is missing.
I have quite an experience on this Mustache.Renderer.register('@...
topic. I'd be happy discussing it.
The only "blessed" name I can think of right now in Rails is the to_param method.
It's quite common and even reccomended to override the to_param
method in Rails for example to return a slug to be used in urls.
I actually like the idea of a to_partial
and to_string
convention. The to_string
would be useful in cases like:
View
{ price: { currency: '£', value: '20.00', to_string: '£20.00' } }
Template
Currency: {{price.currency}} <- '£'
Value: {{price.value}} <- '20.00'
Price: {{price}} <- '£20.00' (to_string)
or
{{#price}}
Currency: {{currency}} <- '£'
Value: {{value}} <- '20.00'
Price: {{.}} <- '£20.00' (to_string)
{{/price}}
or partials...
View
{
people: [
{ first_name: 'John', last_name: 'Lennon', to_partial: 'dead' },
{ first_name: 'Paul', last_name: 'McCartney', to_partial: 'alive' },
]
}
Template
{{#people}}
{{>.}}
{{/people}}
or
{{@people}}
The to_partial
and to_string
keys could even be >
and .
respectively.
I usually try to tell you why I don't like some ideas. It would be nice of you to do the same.
Liquid templates use literals and the point of literals are to be able to insert data into the template. As the premise Mustache is to be logicless and to keep the data in a view object, the introduction of literals doesn't seem a good fit. Next people will want to perform operations on those literals like in Liquid which could end badly.
I have quite an experience on this Mustache.Renderer.register('@... topic. I'd be happy discussing it.
I'm definitely up for suggestions on how to hook into the language as I think this would be a good move for Mustache and provide a nice way to showcase new functionality as well as providing a way for developers to implement their own project specific functionality.
to_partial
You know my take on why special keys are bad (see my comments above)
Liquid templates use literals and the point of literals are to be able to insert data into the template. As the premise Mustache is to be logicless and to keep the data in a view object, the introduction of literals doesn't seem a good fit. Next people will want to perform operations on those literals like in Liquid which could end badly.
Go read https://github.com/mustache/spec/wiki/%5BDiscussion%5D-Logic-Free-vs.-Non-Evaled, including my answers, please. Add you own answer to the wiki if you want. And then come back with more explanations of your opinion, if it still stands.
I'm definitely up for suggestions on how to hook into the language [...]
Sure, here some more reading for you! Those suggestions are all written down in GRMustache documentation. Since you like shortcuts, go check the sample code links. Also don't miss the lambda API, which fixes a few flaws of genuine Mustache lambdas, the filters API, and the mother of all hooks, the template delegate API - now GRMustache recommends using filters, but the delegate was the way to go before their introduction.
All, I've got a fresh new proposal for you.
It's inspired by the fact that the expressiveness of GRMustache comes from its API, not from the Mustache language itself.
So here it is: let's have {{items}}
render the concatenation of dynamic partials, by updating the spec with those four sentences:
{{items}}
the same way as {{#items}}{{.}}{{/items}}
whenever the value attached to items
is an enumeration.{{value}}
, an implementation must fetch the value attached to the key value
. If this value is a lambda, or can be automatically converted to a lambda, the rendering MUST be the result of the lambda call.Now let's see how it fits your needs.
All examples below will use the same templates set:
base.mustache
{{items}}
text.mustache
<p>{{content}}</p>
image.mustache
<p><img src="{{url}}"/></p>
Let's first use a Mustache implementor that only implement MUST rules of the spec:
// User has to provide lambdas in the first place
var text_item = function() { return "{{>text}}"}
text_item.content = 'Some text'
var image_item = function() { return "{{>image}}"}
image_item.url = 'Some URL'
var data = { items: [text_item, image_item] }
Let's now use a Mustache implementation that implements rule 3, but not rule 4. Its documentation says: "If an object has a to_lambda
function property, this function is used for automatic lambda conversion (see Mustache doc)."
// User complies with his Mustache implementation documentation by setting
// the to_lambda property:
var data = {
items: [
{ content: 'Some text', to_lambda: function() { return '{{> text}}' }},
{ url: 'Some URL', to_lambda: function() { return '{{> image}}' }}
]
}
Let's now use a Mustache implementation that implements rule 3 and 4. Its documentation says: "If an object has a to_partial
string property, this value is used for automatic lambda conversion (see Mustache doc)."
// User complies with his Mustache implementation documentation by setting
// the to_partial property:
var data = {
items: [
{ content: 'Some text', to_partial: 'text' },
{ url: 'Some URL', to_partial: 'image' },
]
}
Now, @thelucid, see how this approach is powerful:
A Javascript implementation may state in its documentation: "optional features such as automatic partial and lambda conversions are not supported. You have to provide lambdas objects".
A Javascript implementation may state in its documentation: "in order to get automatic partial conversion, provide the to_partial
key".
A Ruby implementation may state in its documentation: "automatic partial conversion is automatic and based on the class of your object"
A Java implementation may state in its documentation: "automatic partial conversion is based on the interface AutomaticMustachePartia
which defines the getMustachePartialName
method".
An Objective-C implementation may state in its documentation: "automatic partial conversion is based on the conformance to the MustacheMustachePartial
protocol, which defines the mustachePartialName
method".
See? Now if a library wants to mess with the user data, by defining special keys, it can. This is now its own problem. Some other implementations may be able to provide a much cleaner way to implement the dynamic partial feature.
I've just created a pull request over at https://github.com/janl/mustache.js/pull/242
I am using this solution in a couple of projects and it addresses a number of concerns I often hear with regards dynamic partials in Mustache, please see ticket (https://github.com/janl/mustache.js/pull/242) and documentation here:
Really, I urge everyone to have a play with it as it has cleaned up my templates no end.
Kind regards,
Jamie