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
Dynamic partials and partial collections #242
base: master
Are you sure you want to change the base?
Conversation
...can be replaced with:
View:
{
items: [
{ partial: 'text', content: 'Some text' },
{ partial: 'image', url: 'Some URL' }
]
}
Template:
">base.mustache {{@items}} text.mustache <p>{{content}}</p> image.mustache <p><img src="{{url}}"/></p>
...or if more fine grain control is needed:
Template:
">base.mustache {{#items}} <p>{{>.}}</p> {{^items}} text.mustache {{content}} image.mustache <img src="{{url}}"/>
Patch includes tests and documentation, addressing a recurring problem when using Mustache templates e.g. http://stackoverflow.com/questions/2932679/dynamically-render-partial-templates-using-mustache and #241.
I really hope the pull request is accepted as I am already utilising this in a couple of projects and it's a joy to use. I will look at implementing in the Ruby version of Mustache also if accepted.
Kind regards,
Jamie
Things like this should probably be taken up with the spec first, then added to individual implementations: |
Just created ticket here: mustache/spec#54 I do however think that it would be worth applying this patch anyway so that people can see just how useful it is. Think vendor prefixes in browsers, that's how template inheritance made it into hogan.js. |
Vendor prefixes are great, but the analog in Mustache is a |
In fact, there's a "filters" feature which will prolly go out in the next Mustache.php release that does this too: We don't need to stop implementing awesome new things, we just need to be spec-compliant by default and guard the new features with a |
I'm not sure how I'd implement pragma's in mustache.js ...I will investigate. In the meantime, what do you/others think of this patch? I urge you to give it a try as I saw instantly the benefits in my projects. |
I'm thinking we could do with some way of plugging in language features, that way the plugins (middleware) can be used and assessed as a plugin even if they don't make it into the core library. Something like: Mustache.Renderer.register('@', function(name, context, options) {
// My custom tag functionality
return 'the output';
}); Not sure how to go about extend and existing symbol's functionality but something like before/after callbacks could work. |
Your syntax:
and
Assumes 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. This is interesting but I agree with bob that it should be off by default but have an option to turn it on. Further, the {{%PRAGMA}} idea should probably be in the spec itself... @bobthecow, would you agree? |
@thelucid In regards to: Mustache.Renderer.register('@', function(name, context, options) {
// My custom tag functionality
return 'the output';
}); I don't know how you could think of something so terrible... No I like the idea, I need to consider the implementation more, but I'd be interested in hearing what others think. |
The reason I went with assuming a I am using this in production and the {
articles: [
{ partial: 'basic_article', title: 'Title A', content: 'Some text' },
{ partial: 'image_article', title: 'Title B', src: 'image.jpg' }
]
} base.mustache
<div class="articles">
{{@articles}}
</div>
basic_article.mustache
<h1>{{title}}</h1>
<p>{{content}}</p>
image_article.mustache
<h1>{{title}}</h1>
<p><img src="{{src}}"/ ></p> I guess a common ground would be to use Assuming a {{#items}}
<p>{{>.}}</p>
{{^items}} A partial based on
I'm not sure how I'd implement the I'd arguably be more interested in the |
I would appreciate peoples opinions over at mustache/spec#54 if you get a sec as there have been a couple of suggestions that highlight further why a clean solution to "dynamic partials" is needed... namely a pretty ugly workaround using functions that return html (mustache/spec#54 (comment)). |
annnnd i think i'm all caught up on the history of this one (>_<) so... what's the verdict on this dynamic partials stuff? it sure would be helpful to me. at the least, the lamba-based approach shown here mustache/spec#54 (comment) and here #304 (comment) |
@busticated I came up with a Ruby solution that I am happy with in my Mustache implementation (https://github.com/thelucid/tache) which allows for this type of behaviour without a change to the spec but not sure how it will translate to the Javascript version. See the tests starting with |
This seems like a great feature. Was this functionality ever added to mustache in some way? |
I know I'm late to the party, but in case it helps someone - here's a simple function enabling dynamic partials on syntax level without polluting the view. Parentheses in partial's name represent the dynamic property whose value determines the template to use. // For every dynamic partial, a function which renders the subtemplate is added to the view's
// prototype, and their occurrences in the template are replaced with `{{{partial-(name)}}}`,
// now accessible through the prototype.
function render( template, view, partials = {} ){
const prototype = {}
template = template.replace(/\{\{>(.*?\(.+?\).*?)\}\}/g, function(_, name, property){
if( !prototype[name] ){
prototype[name] = function(){
const computed = name.replace(/\((.*?)\)/, (_, property) => this[property])
if( !partials[computed] )
throw new Error(`Dynamic partial "${computed}" does not exist.`)
return render(partials[computed], this, partials)
}
}
return `{{{${name}}}}`
})
view = Object.assign(Object.create(prototype), view)
return Mustache.render(template, view, partials)
} const template = "{{#items}}{{>(type)}}{{/items}}"
const partials = {
image: '<img title="{{title}}">',
text: '<p>{{content}}</p>'
}
const view = {
items: [
{ "type": "image", title: "Some title" },
{ "type": "text", content: "Some text"}
]
}
render(template, view, partials) // <img title="Some title"><p>Some text</p> Using parentheses in property names of the view could shadow the prototype. |
@monkape thanks for sharing your solution. I can't get it to work... Do you happen to have any repos/live code examples using your solution you'd be happy sharing? |
@stuartjnelson Looks like the example above still works fine https://jsbin.com/zejewasebe/edit |
Thanks @monkape for creating the demo. I need to spend some more time getting it to work with my stack. Express app which renders the templates based on JSON data and a |
Hi,
This is a small patch that brings great flexibility when dealing with collections that are going to be rendered using partials. Please see the new documentation below:
With this patch, the following:
View:
Template:
">