Yesterday I updated meteor and my meteorite packages to their latest versions. Today, iron router is not behaving. When I navigate to a parameterized route, the parameter is not loaded. What gives? I have looked at the documentation for iron-router, and it still specifies the same scheme I was using before.
This is the routes file I have created
Router.map(function() {
this.route('home', {
path: '/'
});
this.route('list', {
path: '/:_id',
waitOn: function() {
return Meteor.subscribe('lists')
},
data: function() {
var list = Lists.findOne({
_id: this.params._id
});
Session.set('listId', list._id);
return list;
}
});
});
When I load a page to http://localhost/1234 the path in iron router is correctly set to /1234 but it does not recognize the last bit as a parameter.
I am afraid that what is empty is not your this.params object but rather the list document, at least for the first time the route is being executed. This is caused, of course, by the latency related to fetching server data.
You may be thinking that it shouldn't happen because you have used the waitOn hook. But for this to work you would also need to do two other things:
Router.onBeforeAction('loading');
and define the loading template:
Router.configure({
loadingTemplate: 'someTemplateName'
});
so please update if you haven't done it already.
Related
I recently updated my meteor project and whenever i try to run my project i got this :
Router.route('/', function () {
this.render('Home', {
data: function () { return Items.findOne({_id: this.params._id}); }
});
});
this is my route that should direct the user to "main" template
Router.route('/', {
template: 'main'
});
i used to get similar problem when i first added iron:router package, and the reason was because i haven't implemented it. I believe the way i should implement it is different after the update. please correct me if am wrong
Your router file needs to be included above or in a folder above your client and server folders. It's just there, if router is not contained above client and server than meteor does not digest it properly for the function it serves.
Short answer:
Put router.js where-ever it is that you start your meteor application.
(as opposed to .\client or .\server)
How you configure main template:
Router.configure({
layoutTemplate:'yourMainTemplateName' //main template should have {{> yield}} inside HTML which tells iron:router where to render templates per route
});
Route configuration:
Router.route('/', function () {
this.render('homeTemplateName');
});
Update your question with your new codes if it doesn't work.
I'm not sure why this code works once in a while and fails other times:
var u = Meteor.users.findOne(username:'john');
console.log(u);
When I go to my page for the first time, sometimes the console.log(u) shows some results. But if I press refresh, console.log(u) shows undefined. I can't consistently reproduce one issue or the other. It seems pretty random when i get undefined or a collection. What's wrong with my code? How do I consistently get a collection for the variable u?
Like Christian Fritz said in comment on your question, it's probably a matter of collection not being fully loaded when your code is executed. If you use iron:router, you can use subscribe or waitOn as described there: http://iron-meteor.github.io/iron-router/#the-waiton-option so the page is loaded only when the collections are ready (meaning they are fully loaded).
You can also put it in a helper or use a Tracker Autorun to detect when your entry is available and then do whatever you want to do with it.
Edit: A sample for iron:router below
// myproject.jsx
var Cars = new Mongo.Collection('cars');
if(Meteor.isServer)
{
Meteor.publish("myCollections", function () {
return Meteor.users.find();
});
Meteor.publish("anotherCollection", function(){
return Cars.find();
});
}
//lib/router.js
Router.route('/my-page', {
name: 'myPage',
layoutTemplate: 'myPage',
waitOn: function() {
'use strict';
return [Meteor.subscribe('myCollection'),Meteor.subscribe('anotherCollection')];
},
data: function() {
'use strict';
return Collection.findOne();
}
});
When I start the Meteor server and navigate to my default route, I see the AppLoading template inside MainLayout (as expected), but the main template never loads even after the subscription is loaded.
I've got a really simple routes.js file (below)
autopublish is still turned on.
I seeded the db and can confirm in the browser console that the subscription is there, and there are items in my Services collection.
Probably missing something really simple here.
/*===================
CONFIGURE DEFAULTS
====================*/
Router.configure({
layoutTemplate: 'MainLayout',
loadingTemplate: 'AppLoading',
notFoundTemplate: 'NotFound'
});
/*===================
CONFIGURE ROUTES
====================*/
Router.route('/', { // DEFAULT ROUTE
name: 'main',
template: 'Main',
waitOn: function() {
return Meteor.subscribe('services');
},
data: function() {
return Services.find();
}
});
I'm guessing you do not have a publication? The client is waiting for a "ready" notification from the publication and is not receiving it, hence nothing is loaded. Remove autopublish and start writing publications.
The autopublish package literally just copies the server DB to the client. You can't subscribe to anything if you do not actually have any publications.
When I hit a route that doesn't exist on my Meteor app that uses IR, I get a 200 response with an HTML that (when rendered on a browser) displays a js error on console saying that No route found for path: "/aRoute".
How can a make it return 404?
There don't seem to be a correct (or even working?) way of handling real 404's right now. See this issue for example: https://github.com/EventedMind/iron-router/issues/1055
Even when you try ways which should work, you'll still end up with a 200 status code. Like this code below which should work:
this.route( 'pageNotFound', {
path: '/(.*)',
where: 'server',
action: function() {
this.response.writeHead(404);
this.response.end( html );
}
});
I find this much easier way to show page not found. In router.js
Router.configure({
layoutTemplate: "layout",
loadingTemplate: "loading",
notFoundTemplate: "notFound"
})
Here "notFound" could be any template where you want to show 404 error
this.route('template404', {
path: '/*'
}
Use it at the end of your Router.map, cause this catches every value - if you use at the begining every path will be caught to this
Of course you can make it more complex, for example:
this.route('template404', {
path: '/posts/*'
}
I am developing a meteor applicaton . For routing I am using iron:router .
I am changing some templates by changing a session variable.
Is there any way that without changing the url the user gets an entry in the browser history, that with a browser back the session variable changes back?
My Problem is: Some beta testers tested the app and tried to close some overlays they opened with the browser back button.
I'm not sure I understand your question 100%. But it sounds like you want to set a session variable to a specific value based off of a specific route to control the state of an overlay?
If that's the case, your best bet would be to use an onBeforeAction hook.
Here's how you could do that with a Route Controller:
PostController = RouteController.extend({
waitOn: function () {},
data: function () {},
onBeforeAction () {
Session.set('someSession', 'someValue');
},
action: function () {
this.render();
}
});
If you don't want to use a Route Controller, you can also just add a hook function and specify a route for which the hook should run on.
Edit
Router.onBeforeAction(function () {
Session.set('showOverlay', false);
this.next();
});
You can also specify routes that you don't want this before hook on:
Router.onBeforeAction(function () {
Session.set('showOverlay', false);
this.next();
}, { except: ['admin'] });