Dynamic partials and partial collections #242

Open
wants to merge 1 commit into
from

Projects

None yet

5 participants

@thelucid
thelucid commented Aug 6, 2012

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:

{
  items: [
    { type: 'image', url: 'Some URL', is_image: true },
    { type: 'text', content: 'Some text', is_text: true }
  ]
}

Template:

base.mustache
{{#items}}
  {{#is_text}}
    {{>text}}
  {{/is_text}}
  {{#is_image}}
    {{>image}}
  {{/is_image?}}
{{/items}}

text.mustache
<p>{{content}}</p>

image.mustache
<p><img src="{{url}}"/></p>

...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

@bobthecow

Things like this should probably be taken up with the spec first, then added to individual implementations:

https://github.com/mustache/spec

@thelucid
thelucid commented Aug 6, 2012

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.

@bobthecow

Vendor prefixes are great, but the analog in Mustache is a {{%PRAGMA}} tag. If it's a non-spec feature, it should be off-by-default and explicitly enabled via a toggle. Several great things came into the spec this way (e.g. dot notation, implicit iterators).

@bobthecow

In fact, there's a "filters" feature which will prolly go out in the next Mustache.php release that does this too:

bobthecow/mustache.php#102

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 {{%PRAGMA}} tag :)

@thelucid
thelucid commented Aug 7, 2012

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.

@thelucid
thelucid commented Aug 9, 2012

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.

@devinrhode2

Your syntax:

base.mustache
{{#items}}
<p>{{>.}}</p>
{{^items}}

and

base.mustache
{{@items}}

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?

@devinrhode2

@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.

@thelucid

The reason I went with assuming a partial key is that I like the whole convention over configuration approach.

I am using this in production and the {{@some_collection}} syntax really cleans up templates, it basically says to me at a glance "render a bunch of objects with their own partials":

{
  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 {{@collection}} as I have outlined and the longhand could either be:

Assuming a partial key:

{{#items}}
<p>{{>.}}</p>
{{^items}}

A partial based on my_partial_key:

{{#items}}
<p>{{>.my_partial_key}}</p>
{{^items}}

I'm not sure how I'd implement the {{%PRAGMA}} thing cleanly.

I'd arguably be more interested in the Mustache.Renderer.register functionality as it would allow app specific customisation without hacking Mustache itself. Not sure how you'd use this to add additional functionality to an existing symbol.

@thelucid

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)).

@busticated

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)

@thelucid

@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 ~ for how it's achieved: https://github.com/thelucid/tache/tree/master/test/fixtures

@thelucid thelucid referenced this pull request Apr 17, 2014
Closed

Dynamic Partials #241

@vgracia
vgracia commented Sep 22, 2015

This seems like a great feature. Was this functionality ever added to mustache in some way?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment