Skip to content


Subversion checkout URL

You can clone with
Download ZIP


Syntax for including a single template? {{include}} #155

jeremychone opened this Issue · 14 comments

4 participants


I am just looking at including a template, and what I found is:

{{for #data tmpl="#MyTemplate" /}}

or even

{{if true tmpl="#MyTemplate" /}}

It works, as expected, but I find it a little bit confusing that I need to put a loop or conditional statement to include a single template.

I would have expected something like:

{{include #data tmpl="#MyTemplate" /}}

Am I missing something?


Not sure, but maybe doesn't exists.

Instead, jsRender offer custom tags you can make something like this:

include: function( data ) {
var ret = "";
if( this.props.tmpl) {
ret = jQuery(this.props.tmpl).render(data)

  return ret;



{{for #data tmpl="#MyTemplate" /}} is correct. The {{for}} is not a loop tag, but a "render content for this data" tag, and is designed also for simple template include scenarios. (Note that the data may or may not be an array.)

This is discussed in issue #151. See in particular this comment: #151 (comment).

I think that once the beta is released and full documentation is available, this will become clear thanks to the docs...

If there was a specialized {{include}} tag, then that would be the first time there was a block tag that was only used in the form {{foo tmpl="..."/}} and never in the form {{foo}}inline content{{/foo}} since the latter would need to be a "no-op".


Ok, but {{for ... /}} is also use for loop no?

yes, I have seen #151 and this is where I got the {{for #data...}} but it still look odd to look {{for ...}} as it looks to be use for loop/each as well.

Am I missing something?


It is the same as the render(data) method, which renders once for an object and loops over the data if it is an array... So {{for}} and render() are each used both for rendering against an object, and for looping through an array. This is why it is called {{for}} and not {{each}}. If we did introduce an include it would need to be a tag which does not also accept a data parameter, since otherwise, it gets very similar (almost redundant with) {{for}}, except for not iterating. It would still have the oddity that {{include}}...{{/include}} would be syntactically valid, but a no-op.


Keeping this issue open, for consideration of whether or not to provide a specific {{include}} tag...
(Thanks for the feedback on this...)


Cool, either way is fine with me now that I know the {{for #data ... /}} is the right way of doing it.

I understand the language consistency issue, however, for outside developers the lack of {{include ... /}} might be more distracting than the lack of consistency between the tags.

But I agree, not a easy problem to takle, and taking time to think about this one is good.


Yes, there is a similar issue (#138) around {{else expression}} versus {{elseif expression}} which I am also mulling over...


I've actually been thinking about this issue for a couple of weeks myself, and I just ran aground on it again this morning.

I would suggest that in the current methodology of the {{for}} tag, rolling in the template behavior with it is a bit heavy-handed - it's doing two jobs instead of one. The lack of a standard assignment for the iterated local data as {{each}} used to provide is also notable.

To wit, if I'm composing a template in any other language, I'm likely to do something like (Jinja or pure PHP style):

{{ for i, profile in profilelist }}
    <li>{{ include('profiletemplate', {'profile':profile}) }}</li>
{{ endfor }}

The benefit here is that I can have a wrapper around my included template (via the lis). I can also pass in local data as I need it with a reference that I have assigned, rather than exploding my data into the current space with no container 'handle'. I think this also means that if I'm looping over an associative array or object, I can't get access to the key of the row I'm in - unless I've missed that in the docs and source somewhere. I could be wrong on that.

As I understand it, in JsRender currently, I either must include the li in the sub template and use a single for loop, or something like this:

{{for profilelist}}
        {{for #data tmpl="#profile-template" /}}

Which is, arguably, a bit confusing, and less flexible. Just a thought. Thanks for the awesome project!

@BorisMoore BorisMoore referenced this issue from a commit
@BorisMoore Commit counter 22. Major update, including some BREAKING CHANGES, and…
… many

new features. More samples and documentation for new features will be added
incrementally in coming updates.

Among the changes:

Detailed APIs modified for consistent arguments and use of this
pointer, and for maximum extensibility. See updated samples for usage...

Compiled templates restructured for easier debugging.

View object restructured for clarity.

View now has a type property, e.g. type="item"
Only "item" views have index properties, but to get the index from a nested
view use view.get("item").index.

nodes collection on a view is now a function, view.nodes().

Settings grouped onto a $.views.settings object.
View navigation features improved, with view.get(...) and $.view(elem, ...)
tagCtx object provides improved access to the args and properties of a tag

Adding resources (helpers, converters, tags, etc) to a template now supported
by passing parent template to API. e.g. $.tags({...}, parentTemplate).
Many improvements to custom tags, - used also as part of JsViews integration
for new JsViews Tag Controls. (Instantiation of tags as control instances).

Template inclusion now supported with simpler syntax {{for tmpl=.../))

Fixes for issues #169, #162, #157, #156, #155, #153, #145

There is now (commit 22) support for direct inclusion as follows {{for tmpl="#headerTemplate"/}}.

See sample for usage.

@BorisMoore BorisMoore closed this

I think the confusion came from the fact to use "for" to do "include" I think it would much clearer to provide at least an alias like "{{include tmpl='#headerTeamplate'}}"


Yes, I understand, but I think there are pros and cons to the 'duplicate' tag. So let me give a fairly detailed take on this...

I think there are two aspects.

First, the behavior of the {{for somedata ...}}:
{{for #data tmpl=xxx/}} does already semantically correspond to inclusion, but it is unintuive syntactically for the scenario.
{{for tmpl=xxx/}}
already existed but it did not inherit the data context, which was unintuitive, so that is what I have changed. Now if you don't specify data, you are inheriting the data context. I think that is more intuitive than the previous semantics.

So now we have {{for ...}} meaning: for chosen data and/or template... You can independently choose the data and the template. Data defaults to the current data. template defaults to the content. I think that seems reasonable.

And what that means is that semantically, if you choose a template and don't change the data, you are doing template inclusion.

So if you agree so far, then that leaves the second question:
Should we provide a second way to do template inclusion, and make {{include tmpl=xxx/}} a synonym for {{for tmpl=xxx/}}?

I have some hesitation about the redundancy. We can always add the 'include' tag, but once we have added it we can't remove it. :). So for now, I'm inclined to wait. The fact that some other template languages have an {{include}} is an argument, but I am not yet convinced. JsRender tries to be very economical in the number of concepts and constructs.

For example we could change {{else}} to {{elseif}} but that would prevent us from providing a generic support for any tag (custom or otherwise) of an {{else}} tag. For example we can support:

{{for ...}}
    item template
    no items template

which also exists in some other languages.

For custom tags we can allow:

{{myAccordion label="a"}}
    First section
{{else label="b"}}
    Second section
{{else label="c"}}
    Third section

So my preference is to let a small number of tags support a powerful set of scenarios. Does that make sense?

@BorisMoore BorisMoore referenced this issue from a commit
@BorisMoore Commit 27. Major update - {{else}} with any tag, {{include}} etc.
1: All tags now support one or more {{else}} tags
 - not only {{if ...}}...{{else ...}}...{{else}}...{{/if}}
 - but also {{for ...}}...{{else ...}}...{{else}}...{{/for}}
 - or {{myTag ...}}...{{else ...}}...{{else}}...{{/myTag}}.

 The {{else}} tag(s) will in effect split the content of the
 {{myTag}}...{{/myTag}} block into multiple blocks.

 Each tag implementation can define specific behavior for the {{else}}

 Example: Add an {{else}} to {{for}}...{{/for}} to provide an
 'if array is empty' section.

 - See
 for an advanced interactive example with JsViews.
 - See the updated
 for an interactive example of {{myTag}}...{{else}}...{{/myTag}}

2: There is now an {{include tmpl=.../}} tag, for simple template
 composition, without navigation through data, or iteration over arrays.
 See issue #155

3: There is now a new ‘wrapped template’ feature for providing both
 a template  and block content, so that the template can then ‘wrap’
 the content.

The tag.renderContent() method has been replaced by tag.tagCtx.render()
 on each tagCtx

Advanced custom tag APIs have changed for better support of {{else}} blocks,
 and better navigation through the tag hierarchy.

Update: With commit 27 there is now an {{include tmpl=.../}} tag, for simple template composition, without navigation through data, or iteration over arrays.




The thread above caused slight confusion to some :). So to give a bit of context to the outcome: I mulled over the pros and cons, and reached the conclusion that adding the {{include}} tag does help initial discoverability of how to do simple composition - and reduces possible confusion as to how composition, navigation and iteration interrelate. (Though at the cost of an additional tag). Hence the final design...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.