Hi I'm following the Discover Meteor book, and I'm in Chapter 5-3. I have the router.js and post_item.html precisely as the book, and for every url, I get something like /posts/undefined<id>. I can't figure out why undefined is present in front of every id. Below is my relevant code:
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
waitOn: function() { return Meteor.subscribe('posts'); }
});
Router.route('/', {name: 'postsList'});
Router.route('/posts/:_id', {
name: 'postPage',
data: function() { return Posts.findOne(this.params._id); }
});
<template name="postItem">
<div class="post">
<div class="post-content">
<h3>{{title}}<span>{{domain}}</span></h3>
</div>
Discuss
</div>
</template>
This was an issue caused in the 1.0.8 release as you can check here. Update the package to the 1.0.9 release typing in the console meteor update or manually meteor add iron:router#1.0.9 and it should work.
Related
I have a meteor app using iron router for navigation. I have a layout file that renders on every page. Although there's a page where I don't want the layout file to be displayed/rendered. I bet there exists an elegant way to achieve so but unfortunately I haven't found so yet.
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
notFoundTemplate: 'notapage'
});
Router.route('dataNotFound', function() {
this.render('notapage');
});
Router.route('test/qwerty', function() {
this.render('abc');
}, {
name: 'abc',
waitOn: function() {
return [
Meteor.subscribe('testSubscription')
];
}
});
Layout file :
<template name="layout">
<nav class="navbar navbar-default navbar-fixed-top">
...
</nav>
<div class="clearfix"></div>
<div class="page-container">
{{>yield}}
</div>
<div class="page-footer">
...
</div>
If the route equals abc, I dont want the layout.html file to be rendered/displayed.
You can override the default layout file on an individual Route definition, see: http://iron-meteor.github.io/iron-router/#layouts
Router.route('/post/:_id', function () {
this.layout('ApplicationLayout');
});
The documentation also describes how to render templates into different yield regions in the same layout template.
I'm new to Meteor and have limited experience with javascript. I've searched all the stack post and the web for a good tutorial on how to use the Iron Router package to route static pages and just can't seem to figure it this out. I would love to have someone help me understand how to setup a router.js file for Home and About. I've played with my code a lot but this is what I had before posting here. Conseptually I seem to be struggling to grasp how the routing works and all the various features of iron router and then connecting these routes into a nav bar where I can navigate between them. Thank you in advance for any help you can provide.
client/templates/application/layout.html
<template name="layout">
<div class="container">
{{> yield}}
</div>
</template>
lib/router.js
Router.configure({
layoutTemplate: 'layout'
});
Router.route('/', function () {
this.render('home', {
template: 'home'
});
this.render('about', {
template: 'about'
});
});
templates/home.html
<template name="home">
<div class="container">
<h2>Home</h2>
</div>
</template>
The code you have above looks correct.
One quirk is you're rendering two pages for your / route. You should have this:
Router.route('/', function () {
this.render('home', {});
});
Router.route('/about', function() {
this.render('about', {});
});
Remember this.render takes the first param as the template, so there's no need to define it separately anymore.
And a new about.html page:
<template name="home">
<div class="container">
<h2>Home</h2>
</div>
</template>
Now you can use the / and /about pages (at least I hope i've not missed anything)
You can have 3 templates on your folder
Client/Views
with the name of
about.html
main.html
admin.html
layout.html
(for example)
So in the about.html you have this
<template name="about">
<h1> hello from about page
</template>
<template name="main">
<h1> hello from about page
</template>
<template name="admin">
<h1> hello from about page
</template>
the Layout.html file need con taints this yield rendered.
<template name="layout">
{{> yield}}
{{admin}}
{{about}}
{{main}}
</template>
So you can use layout template as a master page and calling that 3 templates separates by a route, how to assign a route and telling meteor to use that layouts, well use this js code
JS
Router.configure({
layoutTemplate: 'layout'
});
Router.map(function(){
this.route('admin', {path: '/admin'});
});
Router.map(function(){
this.route('about', {path: '/about'});
});
Router.map(function(){
this.route('main', {path: '/'});
});
At least this works for me bro, hope this work for you
I have the following setup in my Iron Router config:
Router.map(function () {
this.route('test', {
path: '/test',
template: 'test'
});
this.route('test_post_pay', {
path: '/test/:optionalParm?',
template: 'test',
data: {
message: 'thank you for donation'
}
});
});
As you can see, they both point to the same template but one supplies a message variable, is there a way to check for this variable in my Meteor code when the page loads? I want to pop a modal up if there is a message being provided by Iron Router
You can use a conditional statement in your handlebars template.
In this case it would be
{{#if message}}
<div class="modal">{{message}}</div>
{{/if}}
I am new to Meteor and I'm trying to set the data context in a page that displays one passage. I need to access the data in passage_item.js Template.passageItem.rendered but no context is set at that point. I think I need something like {{#with passage}} but "passage" does not exist in one_passage.html.
Here are some code snippets. Thanks.
router.js
Router.map(function() {
this.route('passagesList', {path: '/'});
this.route('onePassage', {
path: '/passages/:_id',
data: function() { return Passages.findOne(this.params._id); }
});
});
one_passage.html
<template name="onePassage">
{{> passageItem}}
</template>
passage-item.html
<template name="passageItem">
<div class="passage">
<div class="one-passage">
<h4>{{title}}</h4>
<div class="passage-content">
{{content}}
</div>
</div>
</div>
passage_item.js
Template.passageItem.helpers({
});
Template.passageItem.rendered = function() {
Meteor.defer(function() {
$('.passage-content').lettering('words');
//I want to be able to access the data object here. I have a list of words that are highlighted
});
};
Collection
Assuming you created your Passages collection like this and you've got autopublish turned on (which it is by default):
Passages = new Meteor.Collection('passages');
Router Map
And you mapped your router like this:
Router.map(function() {
this.route('onePassage', {
path: '/passages/:_id',
template: 'passageItem' // <-- to be explicit
data: function() {
return Passages.findOne(this.params._id);
}
});
});
Template
And your template looks like the template below:
<template name="passageItem">
<div class="passage">
<div class="one-passage">
<h4>{{title}}</h4>
<div class="passage-content">
{{content}}
</div>
</div>
</div>
</template>
The scope of 'this' in the template will be set to document returned by the Passages.findOne selector.
If the template doesn't render that means you're either searching for passage that doesn't exist, or your passage is missing title or content fields.
Rendered Function
Now for the last part of your question. The scope of 'this' in a rendered function is set to the template instance. So if you need to access the template data try this:
Template.passageItem.rendered = function() {
console.log(this.data); // you should see your passage object in the console
};
As of Meteor 1.0.3.1, the new Iron Router data selector appears to be...
Template.TemplateName.rendered = function() {
console.log(UI.getData());
};
I assume a passage consists of {'title':'', 'content':''}
Then this should work:
in router.js
Router.map(function() {
this.route('passagesList', {path: '/'});
this.route('onePassage', {
path: '/passages/:_id',
data: {
passage: function() { return Passages.findOne(this.params._id); }
}
});
});
in passage-item.html:
<template name="passageItem">
{{#each passage}}
<div class="passage">
<div class="one-passage">
<h4>{{title}}</h4>
<div class="passage-content">
{{content}}
</div>
</div>
</div>
{{/each}}
</template>
I have an application built with Meteor that uses Iron Router. My layout uses multiple yield templates and I'd like to pass through different data to each one.
It successfully passes through tasks to the tasksList template, but doesn't pass through selectedTask to the taskDetail template.
Is it possible to have multiple data sources and is this the right way to go about it? And if yes, then why is it not working?
Thanks in advance! :-)
Router.map(function() {
this.route('tasksList', {
path: '/',
layoutTemplate: 'layout',
template: 'tasksList',
yieldTemplates: {
'taskDetail': {to: 'rightTemplate'}
},
data: {
tasks: function(){ return Tasks.find() },
selectedTask: function() { return Tasks.findOne() }
}
});
});
<template name="layout">
<section class="wrapper">
<div class="left-pane">
{{yield}}
</div>
<div class="right-pane">
{{yield 'rightTemplate'}}
</div>
</section>
</template>
<template name="tasksList">
<ul>
{{#each tasks}}
<li>{{detail}}</li>
{{/each}}
</ul>
</template>
<template name="taskDetail">
{{#each selectedTask}}
<div>{{detail}}</div>
{{/each}}
</template>
You are returning selectedTask as a single object (with findOne), but in the taskDetail template, you use {{#each selectedTask}}{{detail}}{{/each}}. What happens if you simply have {{detail}} as the body of that template?
Sorry, both those methods work for me now. I must have had a wrong template name or something similar.
You can have multiple data sources as shown in the examples above.