Meteor.js Iron Routing :_id dynamic route confusion - meteor

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?', {

Related

Pulling data from collection using Iron router

I have a small issue. The below code snippet works well if i directly dump it in the body tag
{{#each tasks}}
<ol> <li>Router Name: {{ routerName }}</li>
<li>Router Enable: {{Enable}}</li></ol>
{{/each}}
However, when I wrap it within a template and try call it via a route (iron router), it fails to show the query result.
<template name ='ManagementConfig'
{{#each tasks}}
<ol> <li>Router Name: {{ routerName }}</li>
<li>Router Enable: {{Enable}}</li></ol>
{{/each}}
</template>
Route.js:
Router.route('/ManagementConfig',{ name:'ManagementConfig' });
Everything apart from the above works well within the template and the route. Where am I going wrong?
Your ManagementConfig template don't have access to tasks object. You can fix this by creating a helper method and passing the data.
Template. ManagementConfig.helpers({
'tasks': function(){
//Change this to your task data
return Lists.find({}, {sort: {name: 1}});
}
});

Meteor: Spacebars each parameter

I'm new to Meteor.js and have run into a problem.
I am passing in a user object to a profile template e.g.:
{
_id: "D8JpXRQskm3grykjg",
username: "foo",
profile: {communities: ["AkGCakz6mSgMb8qyS", "j8aB3i5iscrC4ehkA"]},
}
<template name="profile">
<h1> {{username}}: {{_id}} </h1>
<h3>Communities</h3>
<hr>
{{#each profile.communities}}
{{> communityItem}}
{{/each}}
</template>
The problem is I've already written a communityItem template that I am using elsewhere which accepts the communityName. Is there a way that I can write a helper function, passing in the communityIds list that would return a list of community names? I would like:
...
{{#each getCommunityNames(profile.communities)}}
{{> communityItem}}
{{/each}}
...
I could very well be approaching the problem the wrong way or not writing in a "Spacebars" fashion. Thanks!
sure you can:
Template.myTemplate.helpers({
getCommunityNames: function(commIds) {
var communities = Communities.find({_id: {$in: commIds}}).fetch();
return _.pluck(communities, 'name'); // returns ['Name 1', 'Name 2'];
}
});
Note, the syntax method param not method(param)
{{#each getCommunityNames profile.communities}}
{{>communityItem}}
{{/each}}

Meteor iron-router - Can I have multiple data sources in the route?

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.

Pass context to yield when using Meteor Iron Router

I am starting to use Iron Router in my Meteor app and its yields for templating.
I've recently run into a problem where I can't start a named yield with a context, as follows:
{{#with context}}
{{yield 'subtemplate'}}
{{/with}}
and get this error Sorry, couldn't find a yield named "subtemplate". Did you define it in one of the rendered templates like this: {{yield "subtemplate"}}?
If I remove the {{#with}} block expression, I am able to render the yield.
Does anyone know of a good way to pass the context to a named yield?
I have posted my problem as an issue on the iron-router github project, but haven't gotten any solution yet.
Would appreciate any help.
EDIT 1/1/2014:
So my code looks like this:
// main template for the route
<div class="form-container">
<div class="form">
{{yield 'section'}}
</div>
</div>
The logic to get the yield section to display
// router.js
ApplyController = RouteController.extend({
before: function() {
var section = this.params.section || 'personal-info';
Session.set('current', section);
},
action: function() {
var section = Session.get('current');
this.render();
this.render(section, {
to: 'section'
});
},
data: function() {
return {
app: Applications.findOne({user: Meteor.userId()})
}
}
});
Example of one of the section template:
<template name="education">
{{#with app}}
<form id="education" name="education" class="fragment" method="post" action="">
<h2>Education</h2>
<div class="form-group">
<label for="college" class="control-label">College/ University</label>
<select class="form-control" id="college" name="college" placeholder="Select a College/ University">
<option value="">Select a College/ University</option>
{{#each colleges}}
<option value="{{slug}}" {{selected slug ../college}}>{{name}}</option>
{{/each}}
</select>
</div>
<!-- other content here -->
</form>
{{/with}}
</template>
Using the {{#with app}} block is how I currently get around this issue, but because I have 10 different section templates, I have to put that in all of them.
You pass a data context in the router using ironrouter. You can't pass it this way because if you pass a route in the router it would override the route's data context.
It might however work with the shark branch of ironRouter which is based off Meteor UI since it uses {{>yield}} instead of {{yield}}.
You can use this though:
Route specific data context
Router.map(function() {
this.route('template', data: function() { return Something.find() });
});
You basically pass the context using the data param. It might be easier to do it this way than to use {{#with context}} because you can use more dynamic data which is different for each route.
You might have tried this, I'm a bit unsure on whether it would go to a named yield's template.
Using an ordinary Template helper for the template
Template.templateInYieldName.helper = function() {
return Something.find();
}
Then you can use something like {{helper.name}} in your named yield.
Global data context with handlebars helper
If you intend to use data for all the routes you can use a Handlebars global helper. i.e
Handlebars.registerHelper('todaysDate', function() {
return (new Date).toString();
});
then just use {{todaysDate}} in any of your templates. You can use your data instead of a date instead.

Cannot read property '_liveui' of null

I'm getting client side errors(console.log ones) but my app works(I can add users)
The error is the following:
Uncaught TypeError: Cannot read property '_liveui' of null
The project is in my repo:
https://github.com/thiagofm/statusfyit
What is happening?
Meteor has updated its API a bunch since this question was asked, so the original code no longer runs directly.
Using jQuery.html to insert the results of rendering a template is not the normal approach. It is better to use the handlebars template include functionality.
For example, replace:
$().ready(function(){
hello = Meteor.ui.render(function(){
return Template.hello();
});
$('body').html(hello);
});
With:
<body>
{{> hello}}
</body>
To render different things depending on the state of the application, use the 'Session' object to conditionalize includes. For example:
<template name="foo">
{{#if showNewUserDialog}}
{{> newUserDialog}}
{{else}}
other stuff
{{/if}}
</template>
<template name="newUserDialog">
some stuff
</template>
and
Template.foo.showNewUserDialog = function () {
return Session.get('showNewUserDialog');
};
Template.other.events({
'click #new_user': function () {
Session.set('showNewUserDialog', true);
}
});

Resources