Luckily, the solution to this entire problem and any other problems like it has been provided to the Meteor API in the form of the Blaze package, which is the core Meteor package that makes reactive templates possible. If you take a look at the linked documentation, the Blaze package provides a long list of functions that allow for a wide range of solutions for programmatically creating, rendering, and removing both reactive and non-reactive content.
In order to solve the above described problem, you would need to do the following things:
First, anticipate the different HTML chunks that would need to be dynamically rendered for the application. In this case, these chunks would be <div>{{name}}</div>
and <div>{{age}}</div>
, but they could really be anything that is valid HTML (although it is not yet part of the public API, in the future developers will have more options for defining this content in a more dynamic way, as mentioned here in the documentation). You would put these into small template definitions like so:
<template name="nameDiv">
<div>{{name}}</div>
</template>
and
<template name="ageDiv">
<div>{{age}}</div>
</template>
Second, the definition for the firstTemplate
template would need to be altered to contain an HTML node that can be referenced programmatically, like so:
<template name="firstTemplate">
<div></div>
</template>
You would then need to have logic defined for your firstTemplate
template that takes advantage of some of the functions provided by the Blaze package, namely Blaze.With, Blaze.render, and Blaze.remove (although you could alter the following logic and take advantage of the Blaze.renderWithData function instead; it is all based on your personal preference for how you want to define your logic - I only provide one possible solution below for the sake of explanation).
Template.firstTemplate.onRendered(function() {
var dataContext = Template.currentData();
var unrenderedView = Blaze.With(dataContext, function() {
// Define some logic to determine if name/age template should be rendered
// Return either Template.nameDiv or Template.ageDiv
});
var currentTemplate = Template.instance();
var renderedView = Blaze.render(unrenderedView, currentTemplate.firstNode);
currentTemplate.renderedView = renderedView;
});
Template.firstTemplate.onDestroyed(function() {
var renderedView = Template.instance().renderedView;
Blaze.remove(renderedView);
});
So what we are doing here in the onRendered
function for your firstTemplate
template is dynamically determining which of the pieces of data that we want to render onto the page (either name or age in your case) and using the Blaze.With()
function to create an unrendered view of that template using the data context of the firstTemplate
template. Then, we select the firstTemplate
template element node that we want the dynamically generated content to be contained in and pass both objects into the Meteor.render()
function, which renders the unrendered view onto the page with the specified element node as the parent node of the rendered content.
If you read the details for the Blaze.render()
function, you will see that this rendered content will remain reactive until the rendered view is removed using the Blaze.remove()
function, or the specified parent node is removed from the DOM. In my example above, I am taking the reference to the rendered view that I received from the call to Blaze.render()
and saving it directly on the template object. I do this so that when the template itself is destroyed, I can manually remove the rendered view in the onDestroyed()
callback function and be assured that it is truly destroyed.