Thanks again for this awesome router. I'm having an issue with yield not yielding where it should. Like most errors, this one is probably caused somewhere between the chair and the keyboard so I'd appreciate your help!
My Template html is quite simple.
<body>
{{> layout}}
</body>
<template name='layout>
<!--wrapper tags -->
{{> nav}}
<!--more wrapper tags -->
{{yield}}
<!--close wrapper tags -->
{{> footer}}
<!--close wrapper tags -->
</template>
When this renders, I see (in order):
NAV > FOOTER > NAV > YIELD > FOOTER
I tried putting all the wrappers and {{>nav}} and {{>footer}} into the main body tag, leaving only {{yield}} in the layout template. When I do that, I get NAV > FOOTER > YIELD.
In both cases, my router js is identical:
if (Meteor.isClient) {
Router.configure({
layoutTemplate: 'layout'
});
Router.map(function () {
this.route('home', {
path: '/',
template: 'home',
after: function () {
addLabel(this.path);
}
})
//more routes
});
}
I'm sure it's something silly I've done but would appreciate any help you might offer.
Thanks in advance,
db
Remove the {{> layout}} from body tag.
<body>
<!-- no template here, router will add layout automatically -->
</body>
<template name='layout'>
<!--wrapper tags -->
{{> nav}}
<!--more wrapper tags -->
{{yield}}
<!--close wrapper tags -->
{{> footer}}
<!--close wrapper tags -->
</template>
And you are missing ' in < template name='layout>...
Related
I have a template (navBarContent) that I is passed a "title" when I insert it.
I am then able to access {{title}} within that template, but it is not possible to access it within a {{#contentFor}} block embedded in the navBarContent template:
<template name="map">
{{>navBarContent title="MAP"}}
... other content ...
<template>
<template name="navBarContent ">
{{title}}
{{#contentFor "headerTitle"}}
<h1 class="title">{{title}}</h1>
{{/contentFor}}
</template>
I already tried to "forward" the title:
<template name="navBarContent ">
{{title}}
{{#contentFor "headerTitle" title="MAP"}}
<h1 class="title">{{title}}</h1>
{{/contentFor}}
</template>
which produces the following error:
First argument must be a function, to be called on the rest of the arguments;
EDIT:
Ok. I think the data scopes are a the following:
<template name="layout">
{{> yield "headerTitleRenderedInLayout"}}
{{> yield}}
</template>
<template name='map'>
{{> yield "headerTitleRenderedInTemplate"}}
{{>navBarContent title="PARAMETER_TITLE"}}
</template>
<template name="navBarContent">
{{title}} <!-- output: PARAMETER_TITLE -->
{{#contentFor "headerTitleRenderedInLayout"}}
<h1 class="title">{{title}}</h1> <!-- output: LAYOUT_DATA_TITLE -->
{{/contentFor}}
{{#contentFor "headerTitleRenderedInTemplate"}}
<h1 class="title">{{title}}</h1> <!-- output: TEMPLATE_DATA_TITLE -->
{{/contentFor}}
</template>
Above outputs are produced when I use the following router options:
Router.route('/map', function () {
this.layout("layout", {
data: function() {
return { title: "LAYOUT_DATA_TITLE" }
}
});
this.render('map', {
data: function() {
return { title: "TEMPLATE_DATA_TITLE" }
}
});
});
My app has a navbar that is defined in my main layout and I therefore need to set the datacontext for the layout in my route. So far so good, but I want to set that data context based on the value that I pass via:
{{>navBarContent title="PARAMETER_TITLE"}}
This is just a cosmetic thing, because I prefer to define my navbar content in the different templates rather than the routes.
It works when you pass the data context to the render function because Iron Router handles the contentFor block:
Router.route('/', function() {
this.render('map', {
data: function() {
return { title: 'MAP' }
}
});
});
Then the following template shows MAP twice:
<template name="map">
{{> navBarContent }}
{{> yield 'anotherBlock'}}
</template>
<template name="navBarContent">
<div>
In "map": {{title}}
</div>
{{#contentFor 'anotherBlock'}}
<div>
In contentFor: {{title}}
</div>
{{/contentFor}}
</template>
As the title says, this.render does not render a template it's provided with. This is the code in router.js:
Router.configure({
layoutTemplate: 'main'
});
Router.route('/', function(){
this.render('postsList');
});
The file containing the layout template, main.html:
<template name='main'>
<div class='container'>
<header class='navbar'>
<div class='navbar-inner'>
<a class='brand' href='/'>MyApp</a>
</div>
</header>
<div id='main' class='row-fluid'>
{{> yield}}
</div>
</div>
</template>
And the file containing the postsList template which is passed to this.render() function
<template name='postsList'>
<div class='posts'>
{{#each posts}}
{{> postItem}}
{{/each}}
</div>
</template>
So when I go to localhost:3000/ the page displays only the main template and not the postsList template. However, there is no error, unless I completely remove Router.route(...), at which point it will display the standard 'route not found' error.
Also, I tried not using the global template, but a route template, by removing Router.configure(...) and adding this.layout('main') to Router.route(...). The browser then displays nothing.
Your code is perfectly fine. I also came across this issue. The iron:router package seems to be missing the ejson dependancy.
Add the ejson to your app and it should work.
meteor add ejson
I'm sure when iron:router is updated this will be resolved.
I'm using alethes:pagination but I don't understand how to make it work. I have 4 posts in my collection and I want to display 2 per page. Here's the code.
app.js
BlogPosts = new Mongo.Collection("blogPosts");
if (Meteor.isClient) {
Template.body.helpers({
blogPosts: function() {
return BlogPosts.find({});
}
});
}
Pages = new Meteor.Pagination(BlogPosts, {
itemTemplate: "post",
perPage: 2
});
app.html
<head>
<title>pagination</title>
</head>
<body>
{{> pages}}
{{> pagesNav}}
</body>
<template name="post">
{{title}}
</template>
You have to provide 2 templates name to the alethes backed collection.
One for the page itself, and another for the items of your paginated content.
In your JS
PaginatedStuff = new Meteor.Pagination(Polls, {
perPage:6,
templateName: 'paginatedStuff',
itemTemplate: 'stuffListItem'
});
Where you want to have your paginated content :
{{>paginatedStuff}}
And finally the two templates
<template name="paginatedStuff">
{{> pages}}
{{> pagesNav}}<!-- bottom navigation -->
</template>
<template name="stuffListItem">
<!-- stuff to display your item here -->
</template>
I am developing a meteor.js application. I have two main templates/pages, home.html and groups.html. I render these templates according to the selection of main menu. In home template, I just show basic informations about the website. But in groups template, I have side menu which has timeline, chat, group blog options, and according to the selection of side menu, I render timeline or chat or groupblog templates inside groups template. I succeeded this with two different methods.
Can you please tell me if any of them is correct approach, and if they both are, which one is better to use?
In the first approach, is there any way to wait to render sub-template until data is ready, like waitOn property in iron-router?
First approach: I am using dynamic template, and rendering and setting data contex of sub-templates by using Session variable.
layout.html
<template name="layout">
<div>
{{> header}}
<div id="main" class="container">
{{> yield}}
</div>
</div>
</template>
groups.html
<template name="groups">
<div class="row">
<div class="row-fluid">
<div class="col-md-9 col-lg-9">
{{> dynamictemplate}}
</div>
</div>
</div>
</template>
dynamictemplate.html
<template name="dynamictemplate">
{{#DynamicTemplate template=getTemplate data=getData}}
Default content when there is no template.
{{/DynamicTemplate}}
</template>
dynamictemplate.js
Template.dynamictemplate.helpers({
getData: function () {
var tempname="timeline";
if(Session.get("menuitemselected")!=null){
tempname =Session.get("menuitemselected");
}
if(tempname=="timeline"){
return {test:123};
}else if(tempname=="calendar"){
return {groupId:this._id};
}
},
getTemplate: function () {
var tempname="timeline";
if(Session.get("menuitemselected")!=null){
tempname =Session.get("menuitemselected");
}
return tempname;
}
});
Second approach, I am defining new routes for all sub-templates in routes, and I am using yield with region property in home template.(I do not know if i am supposed to use yield in any place other than layout.html)
layout.html
<template name="layout">
<div>
{{> header}}
<div id="main" class="container">
{{> yield}}
</div>
</div>
</template>
groups.html
<template name="groups">
<div>
<div class="col-md-3">
{{> sidemenu}}
</div>
<div id="main" class="col-md-9">
{{> yield region="detailrender"}}
</div>
</div>
</template>
router.js
.....
this.route('groupdetail', {
path: '/groupsmain/:_id',
layoutTemplate: 'layout',
yieldTemplates: {
'timeline': {to: 'detailrender'}
},
data: function() { return Groups.findOne(this.params._id);
}
});
this.route('groupdetailcalendar', {
path: '/groupsmain/:_id/calendar',
layoutTemplate: 'layout',
template: 'groupdetail',
yieldTemplates: {
'calendar': {to: 'detailrender'}
},
data: function() { return Groups.findOne(this.params._id);
.....
});
Handlebar conditioning seems not to be working in attributes.
in the .js
if (Meteor.isClient){
Template.cards.myCards = function()
{
return ["something.png"];
}
Template.card.isSelected = function()
{
return true;
};
}
in the .html
<head>
<title>test</title>
</head>
<body>
{{>cards}}
</body>
<template name="cards">
{{#each myCards}}
{{>card}}
{{/each}}
</template>
<template name="card">
<div class="{{#if isSelected}}selectedClass{{/if}}">
{{#if isSelected}}selectedContent{{/if}}
</div>
</template>
Gives me (once rendered)
<div class="<!--data:DQhTaW3zefLpaZQ2k-->">
selectedContent
</div>
Where is my "selectedClass" gone ? Why is it replaced by the commented data block ?
Take the code on GitHub
Problem recognised as a bug and issue closed the problem has been fixed in Blaze