Reputation: 401
I would like the ability to load templates dynamically without explicitly specifying the template.
As an example:
<template name="foo">
</template>
where 'foo' is the template, I would like the ability to load it dynamically by calling some method:
Meteor.render(Meteor.loadTemplate('foo'));
Is this possible?
Upvotes: 21
Views: 25217
Reputation: 152036
Here's how to dynamically render templates, as of Meteor 0.9.4 - 1.0. All other answers were obsolete at the time of this writing.
Let's say you're editing a bunch of records, or creating a new one, and want to render either the update
template, or the new
template, based on some Session variables.
There are two ways to do this:
1) This is the officially recommended method for Meteor 0.9.4 or newer - it uses Template.dynamic
:
<template name="records">
{{> Template.dynamic template=whichOne}}
</template>
<template name="recordUpdate">
...
</template>
<template name="recordNew">
...
</template>
Template.records.helpers({
whichOne: function () {
return Session.get('edit') ? 'recordUpdate' : 'recordNew'
// note that we return a string - per http://docs.meteor.com/#template_dynamic
}
});
2) This works in various Meteor versions, but isn't recommended officially because it's unclear that the template is chosen dynamically:
<template name="records">
{{> whichOne}}
</template>
{{! Note how "whichOne" is indistinguishable from a constant template name... }}
{{ ...like "recordUpdate" or "recordNew" below. }}
<template name="recordUpdate">
...
</template>
<template name="recordNew">
...
</template>
Template.records.helpers({
whichOne: function () {
return Session.get('edit') ? Template.recordUpdate : Template.recordNew
// note that we return a Template object, not a string
}
});
To pass a data context to the template, use:
{{> Template.dynamic template=whichOne data=myData}}
Upvotes: 37
Reputation: 827
Meteor 0.8.x Legacy
Using Joc's answer as a guide, I've achieved similar using http://docs.meteor.com/#template_call, but using a helper instead, as suggested by the docs:
When called inside a template helper, the body of Meteor.render, or other settings where reactive HTML is being generated, the resulting HTML is annotated so that it renders as reactive DOM elements
My client.js looks a bit like this:
Template.myPageTemplate.helpers({
dynamicTemplate: function() {
// conditional logic can be added here to determine which template to render
return Template.myDynamicTemplate();
}
});
and my html looks like this:
<template name="myPageTemplate">
<h1>My Template</h1>
{{{dynamicTemplate}}}
</template>
<template name="myDynamicTemplate">
<h1>My Dynamic Template</h1>
</template>
Upvotes: 0
Reputation: 392
Meteor 0.9.x New API
Dan Dascalescu pointed out Meteor now has built-in dynamic templates! This is nice because you do not need to include the extra code as seen in previous versions.
{{> Template.dynamic template=template [data=data] }}
For Meteor 0.8.x Legacy
Dynamic Template Without Data: Boris Kotov's updated Blaze (0.8.0) answer is on the right track (taken from the latest docs), but it doesn't work as-is for me. I got the following to work:
{{> dynamicTemplate name=myDynName}}
<template name="dynamicTemplate">
{{#with chooseTemplate name}}
{{> template}}
{{/with}}
</template>
Template.dynamicTemplate.chooseTemplate = function (name) {
return { template: Template[name] };
};
I hope there is a simpler solution, but I needed to wrap the Template in a JSON as shown. Maybe this will help someone else to move forward.
Dynamic Template With Data: If you have and want data to be dynamic, be sure to make a helper method that can react. Be sure to do a Session.set() somewhere to see the effect.
// Inside "myContainingTemplate"
{{> dynamicTemplateWithData name=myDynName data=myDataHelper}}
<template name="dynamicTemplateWithData">
{{#with chooseTemplate name}}
{{#with ../data}}
{{> ..}}
{{/with}}
{{/with}}
</template>
Template.dynamicTemplateWithData.chooseTemplate = function (name) {
return Template[name];
};
Template.myContainingTemplate.helpers({
myDataHelper: function () {
Session.get('myReactiveKey');
}
});
Upvotes: 13
Reputation: 1391
From https://github.com/meteor/meteor/wiki/Using-Blaze
{{> post}}
Template.foo.helpers({
post: function () {
return Template[this.postName];
}
});
Template inclusions now search the namespace of helpers and data for template objects, so it's easy to programmatically choose which template to use. This is a powerful feature, and will allow patterns like assigning one template as a helper of another so that it can be overridden.
Upvotes: 0
Reputation: 37
This would handl dynamic templates both with and without data: (requires Blaze/ Meteor 0.8)
{{> dynamicTemplate name=templateName}}
<template name="dynamicTemplate">
{{#with chooseTemplate name }}
{{#if ../data}}
{{#with ../data }}
{{> .. }}
{{/with}}
{{else}}
{{> this}}
{{/if}}
{{/with}}
<template name="dynamicTemplate">
template javascript:
Template.dynamicTemplate.chooseTemplate = function (name) {
return Template[name];
};
Upvotes: -1
Reputation: 269
for me the easiest way was to just create a function get_dynamic_template, so something like:
var a= get_dynamic_template(template_name,data);
which returns what can be rendered as a normal variable {{a}}
The code for this function is quite simple:
var get_dynamic_template = function(template_name,data)
{
return function(){
return new Handlebars.SafeString(
UI.toHTML(
Template[template_name].extend({data: function () { return data; }}))
);
};
}
Upvotes: -1
Reputation: 1782
Update for blaze:
Dynamically render a template with a given data context
Old:
{{dynamicTemplate name="templateName" data=dataContext}}
Template.foo.dynamicTemplate = function (opts) {
return Template[opts.name](opts.data);
};
New: (Notably, in Blaze, keyword arguments to inclusion or block helpers are bundled into a single object which becomes the new data context)
{{> dynamicTemplate name="templateName" data=dataContext}}
<template name="dynamicTemplate">
{{#with chooseTemplate name}}
{{#with ../data}} {{! original 'data' argument to DynamicTemplate}}
{{> ..}} {{! return value from chooseTemplate(name) }}
{{/with}}
{{/with}}
</template>
Template.dynamicTemplate.chooseTemplate = function (name) {
return Template[name];
}
By the way, I don't really played with it, but this is what I took from the new blaze docs. So I think it should be the way to do it ;)
Upvotes: 2
Reputation: 9859
Based on hillmark's answer, this is the easiest it could get:
Template.main.template = function() {
if (some_condition) {
return Template.A();
} else {
return Template.B();
}
};
With the corresponding .html
<body>
{{> main}}
</body>
<template name="main">
{{{template}}}
</template>
<template name="A">
<h1>Template A</h1>
</template>
<template name="B">
<h1>Template B</h1>
</template>
Edit Doesn't work in Meteor 0.8.0
Upvotes: -1
Reputation: 1059
You have found Meteor.render but what you are missing is the template loading. In the docs it mentions that you can call Template.foo() to return the HTML for a template.
http://docs.meteor.com/#template_call
Putting that together you access the template foo or any other using bracket access so:
var templateName = "foo";
var fragment = Meteor.render( function() {
return Template[ templateName ](); // this calls the template and returns the HTML.
});
Then fragment is your Reactive fragment, so that your template can continue to receive live updates. Your fragment now needs placing in the web page (I use jQuery, so this example does as well):
$("#htmlnode").html( fragment );
$("#htmlnode") is just a node in your DOM where you want the template rendered. And you now have the rendered content in your web page.
Upvotes: 7
Reputation: 2053
I'm just doing it like this, no jQuery required:
EDITED
Template.mainContent.showContentFromRouter = function() {
return Template[Meteor.Router.page()]();
};
In this case I'm using the Meteor Router, and return whatever template that I choose to (from the Router), but you could just do this:
Template.mainContent.showDynamicContent = function() {
return Template['someTemplateYouveDefined']();
};
Upvotes: 2