I've set up two routes in Iron-Router: 'home' (a paged list of all post) and 'doc' (a detail view). The home page loads just fine, but the detail view can only be loaded if the home page has been viewed previously. Otherwise it will render empty – and it can't be used as a permalink.
This will always load:
http://localhost:3000/
This will only load if 'home' has been viewed before:
http://localhost:3000/doc/tZFawq8cgf43hZBaJ
the routes:
Router.map(function() {
this.route('home', {
path: '/'
});
this.route('doc', {
path: '/doc/:_id',
data: function() {
return MyPix.findOne({_id: this.params._id});
}
});
});
the doc template:
<template name="doc">
<h1>{{this.name}}</h1>
<img src="{{ this.url store='OriginalRetinaPix' }}" width="{{ this.metadata.width }}" height="{{ this.metadata.height }}" />
</template>
publish/subscribe:
Meteor.publish('MyPix', function(cursor) {
Counts.publish(this, 'numberOfPosts', MyPix.find(), { noReady: true });
return MyPix.find({}, {sort: {uploadedAt: -1}, limit: 4, skip: cursor});
});
if(Meteor.isClient) {
Session.setDefault('docCursor', 0);
console.log('docCursor: ' + Session.get('docCursor'));
Meteor.autorun(function(){
Meteor.subscribe('MyPix', Session.get('docCursor'));
})
}
btw: the project on GitHub
On your "doc" route, you should use the waitOn in order to have the data ready on page load. Add a loading template in the Router.configure as well
I recommend you to upgrade to the new iron:router routes declarations and also add meteorhacks:subs-manager for better cache on the subscriptions.
This is an example that should work in your case
var subs = new SubsManager();
Router.route('/doc/:_id', {
name: 'doc',
template: 'doc',
waitOn: function() {
return subs.subscribe('aPix', this.params._id);
},
data: function() {
return {
apix: MyPix.findOne({
_id: this.params._id
})
};
}
});
and on the server side create a publications.js
Meteor.publish('aPix', function(id) {
check(id, String);
return MyPix.find(id);
});
Use this.
Router.map(function() {
this.route('home', {
path: '/'
});
this.route('doc', {
path: '/doc/:_id',
waitOn: function(){
return Meteor.subscribe('MyPix');
},
data: function() {
return MyPix.findOne({_id: this.params._id});
}
});
});
Also you subscription should look like this.
Meteor.publish('MyPix', function(cursor) {
//Counts.publish(this, 'numberOfPosts', MyPix.find(), { noReady: true });
return MyPix.find({});
});
Also Add, meteor add sacha:spin, because when you have a lot of people, the subscription will be have a little delay.
Add this to each route.
loadingTemplate: "loading"
<template name="loading">
{{> spinner}}
</template>
Router.onBeforeAction("loading");
Just in case you are showing 100+ images on 'home' and someone enter and have a slow connection, he will think that the page load empty, or something.
You only subscribe to a subset of all the documents. If you directly go to /doc/tZFawq8cgf43hZBaJ, the document with the id tZFawq8cgf43hZBaJ may not be part of the subset of documents you receive on the client.
Note: if this answer is correct, you should be able to directly go to /doc/<id> for those documents showing up first on the home page (on the first page, when the session variable docCursor is 0).
Related
I am using Meteor with iron-router and I'm trying to redirect the user back to the login-page if he is no logged in. But on some routes the onBeforeAction is not called. And as I discovered this has something to do with the data which is returned by the data function on the route.
If data returns null/undefined the onBeforeAction is not called and it displays the layout without the data.
If data returns i.e. an empty object it is calling the onBeforeAction and redirecting to the login-page.
1) Is this the right behaviour or is there something wrong with my route definition?
2) Is it possible that the onBeforeAction function is called before the page is rendered? Because it always show the layout/view for a short moment which is not that nice.
So, I have this route:
this.route('dashboardPortfolio', {
path: ['/dashboard/portfolio'],
layoutTemplate: 'dashboardLayout',
yieldTemplates: {
'header': {to: 'header'},
'dashboardHeader': {to: 'dashboardHeader'},
'footerMain' : {to: 'footer'}
},
notFoundTemplate: 'notFound',
loadingTemplate: 'dashboardLoading',
waitOn: function() {
return Meteor.subscribe("portfolio-edit");
},
data: function() {
var portfolio = Portfolio.findOne({user: Meteor.userId()});
if(portfolio) return portfolio;
else return {};
// return Portfolio.findOne({user: Meteor.userId()});
}
});
and my onBeforeAction:
var OnBeforeActions;
OnBeforeActions = {
loginRequired: function(route, asd, pause) {
if (!Meteor.userId()) {
this.layout('login');
this.render('login');
} else {
this.next();
}
}
};
Router.onBeforeAction(OnBeforeActions.loginRequired, {
except: ['register', 'login', 'about', 'portfolio']
});
Try replacing "except" by "only" in the next line:
except: ['register', 'login', 'about', 'portfolio']
Good luck!
Iron-router is preventing my template from rendering a new page because it seems to believe it is already there.
The routes that I am dealing with are these:
Router.route('/', {
name: 'landingpage',
template: 'landingpage',
onBeforeAction: function() {
this.next();
}
});
Router.route('/chapter/:pathSlug/:chapterSlug', {
name: 'chaptershow',
template: 'chaptershow',
//waitOn: function() {
//return [Meteor.subscribe('users'),
//Meteor.subscribe('ChapterCollection')];
//},
onBeforeAction: function() {
Session.set('currentRoute', 'chapter');
this.next();
}
});
Let's say I have two chapters I want to display:
/chapter/voyage/somestories
/chapter/voyage/someotherstories
From the console I can easily go from the landingpage to either of the voyage pages or vice versa with
Router.go('landingpage');
Router.go('/chapter/voyage/somestories');
However, if I am on /chapter/voyage/somestories and try to go to /chapter/voyage/someotherstories using either
Router.go('/chapter/voyage/someotherstories');
Router.go('chaptershow', {pathSlug: 'voyage', chapterSlug: 'someotherstories'});
the URL in the location bar changes to /chapter/voyage/someotherstories but the new context doesn't load.
How do I get my new chapter to render?
If the data function returns a falsy value like null, the NotFound template will be rendered in my application. This works fine, but now I want also to render the NotFound template, if the route does not exist.
For instance:
this.route('settingsOverviewPage', {
path: '/settings',
data: function() { return Users.findOne(Meteor.userId()); },
waitOn: function() {
if (Meteor.userId()) {
return Meteor.subscribe('ownUser', Meteor.userId());
}
return null;
}
});
If I use this route: /settings12345 for instance, the browser reloads, but it renders the last route.
Any help would be greatly appreciated.
You have to define a "catch-all" route like this :
this.route("notFound",{
path:"*",
template:"notFoundTemplate"
});
It is important that you define this route as the LAST one, otherwise it will catch valid URLs.
I'm following an ember tutorial-
http://coding.smashingmagazine.com/2013/11/07/an-in-depth-introduction-to-ember-js/
and have edited it to include a new model and route. The original tutorial is a CRUD app for a collection of users. I now want to expand the app to deal with a list of subjects that these users might study. The router.jsfile now looks like this-
App.Router.map(function(){
this.resource('users', function(){
this.resource('user', { path:'/:user_id' }, function(){
this.route('edit');
});
this.route('create');
});
this.resource('subjects', function(){
this.resource('subject', {path: '/:subject_id'}, function(){
this.route('edit');
});
this.route('create');
});
});
(Subjects are a separate route because I want to be able to create separate routes for now)
I've added a subjects.js model which looks like this:
App.Subject = DS.Model.extend({
name : DS.attr(),
});
App.Subject.FIXTURES = [{
id: 1,
name: 'History',
}, {
id: 2,
name: 'Biology',
}];
a subjectsController:
App.SubjectsController = Ember.ArrayController.extend({
sortProperties: ['name'],
sortAscending: true // false = descending
});
a subjectsRoute:
App.SubjectsRoute = Ember.Route.extend({
model: function(){
return this.store.find('subject');
}
});
and a template in my index which looks like this:
<script type = "text/x-handlebars" id = "subjects">
<ul>
{{#each subject in controller}}
<li>{{subject.name}}</li>
{{/each}}
</ul>
</script>
I have added all my dependencies and followed the exact same steps in the tutorial as I did for the users CRUD app described in it, but now when I go to my browser, nothing renders. Can anyone see why?
In the tutorial described for you, there is a missing route to catch wrong paths, and redirect to the users route, maybe you need to include it to show something, since there isn't a index route to show some initial page.
Update your code with the following:
router.js
App.Router.map(function(){
this.resource('users', function(){
this.resource('user', { path:'/:user_id' }, function(){
this.route('edit');
});
this.route('create');
});
this.resource('subjects', function(){
this.resource('subject', {path: '/:subject_id'}, function(){
this.route('edit');
});
this.route('create');
});
// this is our 404 error route - see MissingRoute just bellow
this.route('missing', { path: '/*path' });
});
// this handles wrong routes - you could use it to redirect to a 404 route or like here to redirect to the index page
App.MissingRoute = Em.Route.extend({
redirect: function(){
this.transitionTo('users.index');
}
});
My routes looks like this:
App.Router.map(function () {
this.resource('index', { path: '/' }, function() {
this.resource('label', { path: '/label' }, function() {
this.route('notes', { path: '/:label_id' });
});
this.route('manage', { path: '/manage' });
});
});
Users should only visit label.notes and manage routes. I'm trying to find solution how to implement redirection from index for example to label.notes. One of methods described in documentation is:
App.IndexRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('label.notes', 0);
}
});
Here is jsbin with full example http://jsbin.com/UnasOse/1/edit
This works if user navigates by clicking links, but if manage opened by url, or page updated user will be redirected to notes.
So, how to implement redirection only then user opens root url (index)?
Using the your current router mapping, you have the routes index.manage and label.notes.
When the page is refreshed in the index.manage, first it will transition to the parent route, in that case the index, and after to manage. But in you index you have the redirect, so the manage isn't processed.
Just remove of your mapping the resource('index') and update your manage route to reflect the new configuration, so link-to index.manage will become manage, and data-template-name=index/manage to manage etc.
The updated route mapping is the following:
App.Router.map(function () {
// this.route('index', { path: '/' }); generated by ember
this.resource('label', { path: '/label' }, function() {
this.route('notes', { path: '/:label_id' });
});
this.route('manage', { path: '/manage' });
});
You can keep your IndexRoute, because ember create by default a this.route('index', { path: '/' }). So your IndexRoute will execute just when the user go to http://yoursite.com/
You can see that sample in action in this jsbin http://jsbin.com/ucanam/1024/edit