Infinite Scrolling in Iron Router based on Discover Meteor - meteor

I can't seem to get the infinite scrolling to work from Commit 12-5. It says just to mrt add iron-router-progress and everything should work, but my page keeps refreshing. Here's what I'm working with:
PostsListController = RouteController.extend({
template: 'blog',
increment: 20,
limit: function() {
return parseInt(this.params.postsLimit) || this.increment;
},
waitOn: function() {
return Meteor.subscribe('posts', this.limit());
},
posts: function() {
return Posts.find({}, {
limit: this.limit()
});
},
data: function() {
var hasMore = this.posts().count() === this.limit();
var nextPath = this.route.path({
postsLimit: this.limit() + this.increment
});
return {
posts: this.posts(),
nextPath: hasMore ? nextPath : null
};
}
});
Router.map(function() {
this.route('blog', {
path: '/:postsLimit?',
controller: PostsListController
})
})
Router.configure({
layoutTemplate: 'layout',
notFoundTemplate: 'notFound',
});
Everything seems to work EXCEPT when I click load more, the page blinks and jumps back up to the top!

As you can read in the GitHub issues related the commit, it is actually a bug in the 0.7.1 version of iron-router. With the version they used (look up the smart.lock file) it won't refresh and go to the top.

Related

Meteor: Pulling variable from iron router to a template

I am trying to get two variable from the iron router so that I can essentially call them in my temlate such as {{user.telephone}} and {{pic.profilepic}}.
My code in the router is as follows. (Does Not Work!)
Router.route('/profile/:_id', {
name: 'profile',
template: 'profile',
data:function(){
return {
user:Info.findOne({_id:this.params._id}),
pic: Profilepics.findOne({_id:this.params._id})
};
},
subscriptions: function(){
return {
Meteor.subscribe("userInfo"),
Meteor.subscribe( "profilepic");
},
action:function (){
if (this.ready()){
this.render();
}else {
this.render('loading');
}
}
});
I able to do just one variable with the following code. i.e get {{user.telephone}}. Any chance anyone can help me get both variable instead of just one?
enterRouter.route('/profile/:_id', {
name: 'profile',
template: 'profile',
data:function(){
return {
user:Info.findOne({_id:this.params._id})
};
},
subscriptions: function(){
return Meteor.subscribe("userInfo")
},
action:function (){
if (this.ready()){
this.render();
}else {
this.render('loading');
}
}
});
If you are using the latest version of iron router, i suggest you update the code to something a bit more modern.
First you create a general app controller:
ApplicationController = RouteController.extend({
layoutTemplate: 'DefaultLayout',
loadingTemplate: 'loading_template',
notFoundTemplate: '404_template',
});
Then you start to extend it for different purposes:
ProfileController = ApplicationController.extend({
show_single: function() {
this.render('profile');
}
});
After this you can create your routes for the profile part
Router.route('/profile/:_id', {
controller: 'ProfileController',
action: 'show_single',
waitOn: function() {
return [
Meteor.subscribe("userInfo"),
Meteor.subscribe("profilepic")
];
},
subscriptions: function() {
this.subscribe("somethingyoudontneedtowaitfor", this.params._id);
},
data: function() {
if (this.ready()) {
return {
user: Info.findOne({
_id: this.params._id
}),
pic: Profilepics.findOne({
_id: this.params._id
})
};
}
}
});
It might be a bit more code, but it gives you complete control over what it does. Also, using this, while the router is waiting for the subscriptions to be ready, it displays the loading template defined above. If you don't want to display the loading, you move the subscriptions out of waiton.
Return multiple subscriptions as an array from subscriptions function,
Use return [
Meteor.subscribe("userInfo"),
Meteor.subscribe( "profilepic")
];
instead of
return { Meteor.subscribe("userInfo"), Meteor.subscribe( "profilepic"); which has {} mismatch.
In a similar situation I have
data: function() {
var gridId = this.params._gridId;
return (People.find({gridId: gridId})
&& GridLog.find({gridId: gridId}));
},
with the subscribe calls in the waitOn() handler as part of the Boolean status
waitOn: function() {
return (Meteor.subscribe('people', this.params._gridId)
&& Meteor.subscribe('gridlog', this.params._gridId) );
},
You may have more success just &&ing them together in waitOn() (as strange as that seems).

Page not showing single database entry in Meteor

I have set up my app with Iron Router and have a 'post' page where I would like to show a single post according to its ID. However, this page does not show a post, and instead the post template renders blank (although the url and nav are working fine). Here is my code:
router.js
Router.route('postDetail', {
path: '/posts/:_id',
notFoundTemplate: 'postNotFound',
waitOn: function() {
return [
Meteor.subscribe('post')
]
},
data: function() {
var idVar = this.params._id
return posts.findOne({_id: idVar});
}
});
postDetail.html
<template name="postDetail">
{{address}}
</template>
postsPub.js
Meteor.publish('posts', function () {
return posts.find();
});
Meteor.publish('post', function (id) {
return posts.find(id);
});
It looks like your publisher needs an id. Try this in your waitOn:
Meteor.subscribe('post', this.params._id)
I was able to solve this issue by simply removing the 'post' publish function, and including the following route which refers to the 'posts' publish function instead:
Router.route('postDetail', {
path: '/posts/:_id',
notFoundTemplate: 'postNotFound',
waitOn: function() { return Meteor.subscribe('posts'); },
data: function() { return posts.findOne(this.params._id); }
});

Data isnt loaded on page refresh, only on transitions

I currently have a problem with data not being ready upon full page refreshes. I get the following error
TypeError: Cannot read property 'earnings' of undefined
However, the data gets loaded correctly when I transition to the route through a pathFor link from another template.
I have the following route defined:
this.route('overview', {
path: '/overview',
layoutTemplate: 'dashboardLayout',
loginRequired: 'entrySignIn',
waitOn: function() {
Meteor.subscribe('overviewData');
},
data: function() {
return {
earnings: Meteor.user().earnings,
};
},
onAfterAction: function() {
SEO.set({
title: 'Overview | ' + SEO.settings.title
});
}
});
Which subscribes to this publication:
Meteor.publish('overviewData', function() {
if (!this.userId) { return null; }
return [
Meteor.users.find(this.userId, { fields: { earnings: 1} }),
Tabs.find({ userId: this.userId })
];
});
Piece of template referencing data:
<div class="period pull-left">
Period <span class='amount'>{{earnings.period}}</span>$
</div>
Try this.ready() before sending data, and also add return in waitOn function
try the following code
this.route('overview', {
path: '/overview',
layoutTemplate: 'dashboardLayout',
loginRequired: 'entrySignIn',
waitOn: function() {
return Meteor.subscribe('overviewData');
},
data: function() {
if(this.ready()){
return {
earnings: Meteor.user().earnings,
}
}
},
onAfterAction: function() {
SEO.set({
title: 'Overview | ' + SEO.settings.title
});
}
});
EDIT
This works because this.ready() will be true only after the subscriptions which are returned by waitOn() function completed.
In your code your sending the data without checking whther the data is subscribed or not(or the data is sent to client or not). So it return undefined
I think this may be caused by the fact that it takes a moment for the browser to read the cookie data to log back in. Maybe try adding an onBeforeAction for your route that checks if the user is logging in before rerouting.
this.route('overview', {
path: '/overview',
layoutTemplate: 'dashboardLayout',
loginRequired: 'entrySignIn',
waitOn: function() {
Meteor.subscribe('overviewData');
},
data: function() {
return {
earnings: Meteor.user().earnings,
};
},
onBeforeAction: function() {
if (!Meteor.user()) {
if (Meteor.loggingIn())
this.render('loadingTemplate');
}
else {
this.next();
}
},
onAfterAction: function() {
SEO.set({
title: 'Overview | ' + SEO.settings.title
});
}
});
Meteor users are a reactive data source, so the route should run again when loggingIn() is finished and shouldn't throw an undefined error.

Data not accessible in helper block in Meteor

I have autopublish on.
Template.play.helpers ({
title: function () {
wcount = Workouts.find().count();
console.log(wcount);
}
});
This gives me 0.
But if I'm in the developer console of my browser.
Workouts.find().count()
24
I have recently upgraded to 0.8
If I add waitOn to the Router then I get this behavior every other time I load the page.
Router.map(function() {
this.route('splash', {path: '/'});
this.route('play', {
path: '/play',
template: 'play',
waitOn: function() {
return Meteor.subscribe('Workouts')
}
});
After some help from #Christian Fritz it seems that my problem is that its not waiting on my subscription and if the helper doesn't return anything because its undefined then it doesn't get rerun when the data does get loaded.
I have now turned off autopublish. My server/publications.js is:
Meteor.publish('workouts', function() {
return Workouts.find();
});
My router is:
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading'
});
Router.map(function() {
this.route('splash', {path: '/'});
this.route('play', {
path: '/play',
template: 'play',
waitOn: function() {
return Meteor.subscribe('workouts')
}
});
});
in play.js
var workoutsSubcription = Meteor.subscribe('workouts');
console.log("workoutsSubscription.ready() is ",workoutsSubcription.ready());
returns:
workoutsSubscription.ready() is false
once or twice then finally reruns when its fully loaded as true. But shouldn't the waitOn mean that it doesn't run that page until the data is there?
You probably want something like this:
var workoutsSubcription = Meteor.subscribe('workout_count');
Template.play.helpers ({
title: function () {
if(workoutsSubcription.ready()){
wcount = Workouts.find().count();
}
}
});
You would need to publish your subscription on the server as well
Meteor.publish("workout_count", function () {
return Workouts.find();
});

Meteor Iron Router - Why does my app always goes to the base url on refresh or url load

I have a meteor app that uses iron router. Every time I refresh the browser or input a url like http://localhost:3000/gigs my app refreshes back to the base url of just http://localhost:3000
Here is my router.js code
var requireLogin = function() {
if (!Meteor.user() && !Meteor.loggingIn()) {
Router.go('signIn');
this.stop();
}
};
Router.configure({ loadingTemplate: 'loading' });
Router.before(requireLogin, {only: ['tasks', 'gigs']});
Router.map(function() {
this.route('tasks', {
path: '/',
waitOn: function() { return [ Meteor.subscribe('projects'), Meteor.subscribe('tasks') ] },
layoutTemplate: 'twoColMenuLayout',
template: 'tasksList',
yieldTemplates: {l
'taskDetail': {to: 'rightTemplate'}
},
data: {
moduleName: 'projects'
}
});
this.route('gigs', {
path: '/gigs',
waitOn: function() { return [ Meteor.subscribe('gigs') ] },
layoutTemplate: 'twoColMenuLayout',
template: 'gigsList',
yieldTemplates: {
'gigDetail': {to: 'rightTemplate'}
},
data: {
moduleName: 'gigs'
}
});
this.route('gigSubmit', {
path: '/gig-submit',
layoutTemplate: 'oneColMenuLayout',
template: 'gigSubmit',
data: {
pageTitle: 'New Gig'
}
});
this.route('signIn', {
path: '/signIn',
layoutTemplate: 'blankLayout',
template: 'signIn'
});
});
The strange thing is that if I change the 'tasks' path to be '/tasks' instead of '/' this problem doesn't occur and it works as I would expect it to. However when I do that I get a console error message that no '/' is defined. It doesn't seem to break anything but I hate having errors in the console.
I've also tried moving the 'tasks' map to the bottom in case it was matching first on this one and always going there, but that didn't make a difference.
Any idea why this is happening?
Thanks!
I encountered this just recently. You'll want to order the routes from the deepest at the start to the most shallow at the bottom:
this.route('someDeepRoute', {
path: '/deep/route',
});
this.route('gigs', {
path: '/gigs',
});
this.route('gigSubmit', {
path: '/gig-submit',
});
this.route('signIn', {
path: '/signIn',
});
this.route('tasks', {
path: '/',
});

Resources