Why does route to home changes after rendering a template? - meteor

I am just getting started using the iron:router package. These are my project files:
router-example.js
if (Meteor.isClient) {
//some code
}
if (Meteor.isServer) {
//some code
}
Router.route('/', function(){
this.render('Home');
});
Router.route('/hello', function(){
this.render('hello');
});
Router.route('/items', function(){
this.render('Items');
});
Router.route('/serverItem', function(){
var req = this.request;
var res = this.response;
res.end('Hello from the server\n');
}, {where: 'server'});
router-example.html
<body>
<h1>Welcome to Meteor!</h1>
<ol>
<li>This routing doesn't work</li>
<li>Hello Template</li>
<li>Items Template</li>
<li>Server Item</li>
<li>Hard link works</li>
</ol>
</body>
templates.html
<template name = "Home">
<h2>Default: '/' brings you here</h2>
<p>This is the home template</p>
</template>
<template name = "Items">
<h2>This is the items template. Items Page linked using pathFor helper</h2>
</template>
<template name="hello">
<button>Click Me</button>
<p>You've pressed the button {{counter}} times.</p>
</template>
So at the home page "localhost:3000", the "Home" template is rendered by default, as expected. Once I click on the other links:
Hello Template,
Items Template etc.
Those are rendered, but home link specified using the {{pathFor '/'}} helper stops working and I have to use a hard link (localhost:3000) to get back to the home page. Hovering the mouse over that link shows that it's pointing to a different route.
So what am I doing wrong here?

You can specify route name in order to use {{pathFor 'routeName'}}:
Router.route('/', {
name: 'home',
template: 'Home'
})
Look here for full example https://github.com/iron-meteor/iron-router/blob/devel/Guide.md#route-specific-options
If no name is provided, the router guesses a name based on the path

Related

Setting up data contexts in Meteor and Iron Router

I was after some advice please on the best way to set up data contexts for a MongoDB database with Iron Router.
To explain I'm working on a fairly basic film reviews project, and deployed to Modulus at http://reviews-48062.onmodulus.net/
This returns a list of reviews, but would like to use routes to create other pages. I've installed Iron Router locally and have a local MongoDB collection (called tasks) with some data in it.
Have re-written some code to include routing information. This works successfully in displaying the routes, but doesn't seem to pull in any data into the {{each}} statement.
My JS code is as follows:
// define Mongodb collection
Tasks = new Mongo.Collection("tasks");
// set up home route and database query
Router.route('/', function () {
this.render('Home', {
tasks: function () { return Tasks.find({}, {sort: {title: 1}, limit: 10}); }
});
});
// define routes
Router.route('/one');
Router.route('/two');
Router.route('/three');
The HTML code is:
<head>
<title>Iron router sandbox</title>
</head>
<body>
</body>
<template name="Home">
{{> Nav}}
<h1>Home</h1>
<p>This is a test</p>
{{#each tasks}}
<li>
<strong>{{title}}</strong>
<p>Directed by {{director}}</p>
<p>{{review}}</p>
<p>Available on: {{format}}</p>
</li>
{{/each}}
</template>
<template name="One">
{{> Nav}}
<h1>Page One</h1>
<p>Some more text.</p>
</template>
<template name="Two">
{{> Nav}}
<h1>Page Two</h1>
<p>A bit more text.</p>
</template>
<template name="Three">
{{> Nav}}
<h1>Page Three</h1>
<p>Even more text.</p>
</template>
<template name="Nav">
<ul>
<li>
Home
</li>
<li>
Page One
</li>
<li>
Page Two
</li>
<li>
Page Three
</li>
</ul>
</template>
My understanding is that the data context is set up for the "Home" template, so not sure what's wrong with the code.
Any advice much appreciated.
tasks is not a valid property to send to that object. You need to set the data context for IronRouter using data instead. Change tasks to data, then set up a helper on your template to get tasks data:
Template.Home.helpers({
tasks() {
return Tasks.find({}, {sort: {title: 1}, limit: 10});
}
});
You can return a data context with i-r but it needs to be named data:
Router.route('/', function () {
this.render('Home', {
data: function () {
return { tasks: Tasks.find({}, {sort: {title: 1}, limit: 10}); } };
});
});
This will return a data context to your template and then the tasks key will contain a cursor of tasks.

How to route html pages on clicks in meteor?

I am a newbie in Meteor. I am developing an app having a login page that must redirect to certain pages as per the login id.There are certain click events which opens up html pages.I have the hard code data in the pages to check the flow now.I have the html pages as well designed, but I am not able to link them for click events and login. Please help.
Here is one way to do it:
In your HTML file, something like this:
<head>
<title>Duckbilled Platypus</title>
</head>
<template name='layout'>
{{> banner}}
{{> yield}}
</template>
<template name="banner">
<h1 class="chocolatefont">Platypi of the World Unite! (Duckbilled, that is)</h1>
<hr/>
</template>
<template name="main">
<div id="templateMain" name="templateMain">
<h2>RAVES</h2>
<p>No Raves yet</p>
<h2>RANTS</h2>
<p>No Rants yet</p>
<h2>RANDOM</h2>
The Legend of NFN Oscar
<br/><br/>
NFN Oscar's donut
<br/><br/>
Alliteration Station ("Ben's Bizarre Bazaar")
<br/><br/>
Boomeranging Telescopic and Kaleidoscopic Phrase Mazes
<br/><br/>
Acrostics
<br/><br/>
Homonym Homie
</div>
</template>
...and then add whichever templates you want for the pages you want to route to; in my case, it's one for each "href" referenced in the anchor tags (nfnoscar, nfnoscarsdout. etc.)
The "yield" (which means, "insert here whatever the router says corresponds to the URL") requires Iron:Router, which you say you already have.
In your JS file, something like this:
Router.configure({
layoutTemplate: 'layout'
});
Router.route('/', {
name: 'main',
template: 'main'
});
Router.route('/nfnoscar', {
name: 'nfnoscar',
template: 'nfnoscar'
});
Router.route('/nfnoscarsdonut', {
name: 'nfnoscarsdonut',
template: 'nfnoscarsdonut'
});
Router.route('/alliterationstation', {
name: 'alliterationstation',
template: 'alliterationstation'
});
Router.route('/btakpm', {
name: 'btakpm',
template: 'btakpm'
});
Router.route('/homonyms', {
name: 'homonyms',
template: 'homonyms'
});
Router.route('/acrostics', {
name: 'acrostics',
template: 'acrostics'
});
Now, whichever link is clicked, the corresponding page is loaded by means of the "yield" and the Iron Router routing.
You can see this particular app and how it works when you click the links, etc., at my "sandbox" Meteorsite here.

Meteor.js Iron Routing :_id dynamic route confusion

I'm currently working my way though "Your Second Meteor Application" and have been enjoying it so far. Everything I have created works but I do not understand why the following works but the code at the end does not.
Template
<template name="list">
<ul>
{{#each list}}
<li>{{name}}</li>
{{/each}}
</ul>
</template>
<template name="listPage">
<h2>Tasks: {{name}}</h2>
</template>
Route
Router.route('/list/:_id', {
template: 'listPage',
data: function(){
var currentList = this.params._id;
return Lists.findOne({_id: currentList});
}
});
This is giving the expected results. However, I was curious why the following will not work as it seems to be passing the exact same thing. The only differences with the following are:
changing the Router.route('lists/:_id') to Router.route('lists/randomParm')
this.params._id to this.params.randomParm
Template
<template name="list">
<ul>
{{#each list}}
<li>{{name}}</li>
{{/each}}
</ul>
</template>
<template name="listPage">
<h2>Tasks: {{name}}</h2>
</template>
Route
Router.route('/list/randomParm', {
template: 'listPage',
data: function(){
var currentList = this.params.randomParm;
return Lists.findOne({_id: currentList});
}
});
The message I am getting is:
Oops, looks like there's no route on the client or the server for url: "http://localhost:3000/list/TGM9dbRRtspyJy7AR."
Isn't :_id and randomParm holding the same values? An id of list items from the HTML links that are being passed to the routing url and being used to make a mongo call? I don't quite understand how :_id and randomParm are different when I am hitting the same routing URL.
Param shold be with :
So your route will be
Router.route('/list/:randomParm', {
If this param is optional then leave ? after
Router.route('/list/:randomParm?', {

Is there a way to access Iron Router parameter from template in Meteor

I have a route that has a parameter in it and I need to access it from many different templates. Below is one example of the route, there are several routes that are very similar just after the _occasionnId parameter it changes:
For example:
Route 1: /occasions/:_occasionId/cards/
Router 2: /occasions/:_occasionId/tables/
Here is my full code for each route, the only thing that really changes is the route path and the template.
Router.route('/occasions/:_occasionId/cards/', {
template: 'cards',
data: function(){
//var currentoccasion = this.params._occasionId;
//console.log(currentoccasion);
},subscriptions : function(){
Meteor.subscribe('cards');
Meteor.subscribe('tables');
}
});
I need to get the _occasionId parameter into a template that has navigation which goes in on all of these pages. My goal is that from Route 1, you can go to Router 2. But I can't figure out how to add the correct URL in the template.
My template is:
<template name="occasionnav">
<nav>
<div class="nav-wrapper">
<ul class="right hide-on-med-and-down">
<li>cards</li>
<li>tables</li>
</ul>
</div>
</nav>
</template>
In the 'occasionnav' template by ":_occasionId" I need that to be the same parameter as the page currently being viewed be stuck into here.
If anyone has any insight or advice on the best way to approach this I would really appreciate it.
I recommend to use {{pathFor}} if you want to render an internal route in your Meteor application.
You just need to set the proper context and name your routes, for example:
<template name="occasionnav">
<nav>
<div class="nav-wrapper">
<ul class="right hide-on-med-and-down">
{{#with occasion}}
<li>cards</li>
<li>tables</li>
{{/with}}
</ul>
</div>
</nav>
</template>
Router.route('/occasions/:_id/cards/', {
template: 'cards',
name: 'occasions.cards',
data: function() {
return Cards.findOne({_id: this.params._id});
},
subscriptions: function() {
return Meteor.subscribe('cards', this.params._id);
}
});
Router.route('/occasions/:_id/tables/', {
template: 'tables',
name: 'occasions.tables',
data: function() {
return Tables.findOne({_id: this.params._id});
},
subscriptions: function() {
return Meteor.subscribe('tables', this.params._id);
}
});
However, you can also get the router parameters in your template via Router.current().params.
You can pass the _occasionId as a template helper and render it in jade like:
<li>cards</li>
You should try :
Router.route('/occasions/:_occasionId/cards/', function() {
this.layout("LayoutName");
this.render("cards", {
data: {
currentoccasion = this.params._occasionId;
}
});
});
When you use Router.map, it's not exactly the same syntax:
Router.map(function() {
this.route('<template name>', {
path: 'path/:_currentoccasion',
data: function () {
return {
currentoccasion: this.params._currentoccasion
}
}
});
And you can access just like that in your template :
Like an helper
{{ currentoccasion }}
Or on the onRendered and onCreated functions
Template.<template name>.onRendered({
this.data.currentoccasion

Meteor: make layout.html WaitOn a subscription?

I'm trying to make a chat (Template.chatlist) feature that sticks to the bottom of the page (similar to the chat function on Facebook, where the chat box is persistent while the page in the background changes as the user browses to other parts of the site). So I put the chat box in a handlebars template on the layout page (so it's not rendering from the {{>yield}} template). The problem is, it's not waiting on the subscriptions before it loads (there is no route to the layout.html, so I couldn't set a waitOn on it in the router), so it's not able to pull information from my users collection.
I need to know, how can I make the layout.html page wait to load after the subscriptions are properly finished? Of course, I can put the chat template inside every page's yield template to have it wait properly, but is there a way where I don't have to do it this way?
<main class="main container" id="central">
{{> yield}}
{{> chatlist}}
</main>
This is sort of what the layout.html looks like right now. The chatlist template is not waiting on any data subscriptions because it's not in the yield section (and thus not controlled by the router)
I also did Template.chatlist.helpers and registered the user data into a helper, but for some reason when I tested it by console logging Users.count the console returns with zero.
Use a region:
<template name="layout">
<aside>
{{> yield region='aside'}}
</aside>
<div>
{{> yield}}
</div>
<footer>
{{> yield region='footer'}}
</footer>
</template>
Router.map(function () {
this.route('home', {
path: '/',
template: 'myHomeTemplate',
layoutTemplate: 'layout',
yieldTemplates: {
'myAsideTemplate': {to: 'aside'},
'myFooter': {to: 'footer'}
},
waitOn: function() {
// ...
}
});
});
See the Iron Router docs.

Resources