IronRouter dataNotFound on blog post - meteor

I would like show 404 page if blog/xyz don't work. So i've add dataNotFound on my routes.js, but i've no result :
Router.route('/blog/:slug', {
name: 'blogPost',
parent: 'blog',
itemName: function () {
return this.data().post.title;
},
data: function () {
let post = Posts.findOne({
'slug': this.params.slug
});
return {
post,
profil
};
}
});
Router.onBeforeAction('dataNotFound', {
only: 'blogPost'
});
If i test wrong url with blog/ojhojeofje, i don't have 404 page, just post without data.
Do you have any idea ?
Thank you !

First of all, you need to register dataNotFound as plugin instead of in onBeforeAction:
Router.plugin('dataNotFound', { only: ['blogPost'] });
Secondly the dataNotFound plugin works by checking if your route data() returns a falsy value. Since you want to load multiple data object in your data() function, you need to alter your function so that it will return something falsy if the post is not found. For example you can simply do this:
data: function () {
let post = Posts.findOne({
'slug': this.params.slug
});
if (!post) {
return false;
}
...
Note that you also need to make sure that your subscription to the Posts collection is ready before you run data in order to avoid going to the not found page unnecessarily.

Related

Meteor: Publishing all user not working without autopublish package

I would to show a list of all users, in my template.
I have:
//publications.js
Meteor.publish('users', function() {
return Meteor.users.find({}, { fields: {username: 1, profile: 1} });
});
//router.js
Router.route('/users/add/:_id?', {name: 'users.add', controller: 'UserAddController'});
UserAddController = RouteController.extend({
subscriptions: function(){
return [ Meteor.subscribe('hospitals'),
Meteor.subscribe('roles'),
Meteor.subscribe('users') ];
},
action: function() {
this.render('addUser', {
data: function(){
return { hospital_id : this.params._id }
}
});
}
});
//client
Template.listUsers.helpers({
users: function() {
return Meteor.users.find({});
}
});
But the list keep showing only the current logged-in user. I have created a list of users using Account.createUser() function What am I doing wrong?
Thanks.
You have to subscribe to a publication using this.subscribe() in subscriptions hook:
// a place to put your subscriptions
subscriptions: function() {
this.subscribe('items');
// add the subscription to the waitlist
this.subscribe('item', this.params._id).wait();
}
Or use waitOn:
// Subscriptions or other things we want to "wait" on. This also
// automatically uses the loading hook. That's the only difference between
// this option and the subscriptions option above.
waitOn: function () {
return Meteor.subscribe('post', this.params._id);
}
By default, Meteor publishes the current user. I see that you have a addUser template and a listUsers template. The problem is that while addUser is subscribed to the users publication, listUsers is not (this would depend on what else you have in your router of course). To fix this, change the call to this.render to render the listUsers template. Then, your users helper should work, and you can render the information however you like.
I tested this with my own app (the Microscope project from DiscoverMeteor) and it worked for me. Hope it works for you too. Comment here if not, and be sure to accept this answer if it worked. =)

access data from iron-router in rendered function

I'm trying to access data passed from iron router in the javascript function
router.js
this.route('editOrganization', {
path: '/editOrganization',
waitOn: function() {
return [
Meteor.subscribe('organization', this.userId)
];
},
data: function() {
return Organizations.findOne();
}
});
now if I wanted to access a property of organization in html (editCompany.html) I can do the following
{{name}}
but how do I access that same property in the js file
Template.editOrganization.rendered = function() {
//how do I access name?
}
UPDATE:
so if I click a link to edit organization I can get the value via
this.data.name
However, if I reload the page (same url) it throws an error saying data is null.
It is accessible through the rendered function context.
Template.editOrganization.rendered = function() {
var name = this.data && this.data.name;
};
This is confusing for many people but you need to configure the router to actually wait for the subscriptions you returned with waitOn.
Router.onBeforeAction('loading')
You can read the author's explanation here:
https://github.com/EventedMind/iron-router/issues/554#issuecomment-39002306

meteor subscription manager change collection name

I'm using subscriptions manager with iron-router and my problem is this one.
I have a collection "participants" with 2 publications: allParticipants and todayParticipants.
if I go to this page:
Router.map(function () {
this.route('winners', {
waitOn: function () {
return [subs.subscribe('allWinners'),
subs.subscribe('allParticipants')];
console.log("subscribed!");
},
data: function () {
return {
winners: Winners.find(),
participants: Participants.find(),
loginBox: "True"
}
}
});
AllParticipants publication is subscribed and put in cache by the subscription manager package.
If after this, I go to this page:
Router.map(function () {
this.route('participants', {
path: '/',
waitOn: function () {
return subs.subscribe('todayParticipants');
},
data: function () {
return {
participants: Participants.find()
}
}
});
I'm expecting to subscribe only the todayParticipants but as my subscription is automatically named "Participants", It uses the cached subscription from the previous page being allParticipants.
Is there a way to change the name of my subscriptions in order to have each of them in the right cache?
Thanks.
What I do in my waitOn function is first stop my subscriptions like
if (App.subs) {
for (name in App.subs) {
App.subs[name].stop();
}
}
And then I create new subscriptions
App.subs = {
settings: Meteor.subscribe('settings', project),
...
};
return [App.sub.settings, .....];
Hope this helps!
Today, there seems to be no solution to this problem.
More explanation here: https://github.com/meteorhacks/subs-manager/issues/11
What I'm doing now is using a very limited number of subscriptions (filtered mainly on user) and then I create as much data objects as I want filtering my subscriptions in different ways.

How to properly replace this.stop() with pause() on Iron Router blaze integration

When I upgrade Iron Router to blaze integration branch, I began receiving this warning:
"You called this.stop() inside a hook or your action function but you should use pause() now instead"
Chrome console --> iron-router.js:2104 --> client/route_controller.js:193 from package
The code is on client:
Router.before(mustBeSignedIn, {except: ['userSignin', 'userSignup', 'home']});
var mustBeSignedIn = function () {
if (!Meteor.user()) {
// render the home template
this.redirect('home');
// stop the rest of the before hooks and the action function
this.stop();
return false;
}
return true;
}
I tried replacing this.stop() with: pause(), Router.pause() and this.pause() but still does not work. Also I haven't found pause function on iron-router package.
How do I properly replace this.stop() with pause()?
Thanks
From what I can tell the pause function is the first parameter your before hook is getting called with. Not in the docs anywhere, but that's what I gathered from the code and it seems to work.
Here's what I use:
var subscribeAllPlanItems = function (pause) {
var planId = this.params._id;
this.subscribe('revenues', planId).wait();
this.subscribe('expenses', planId).wait();
};
var waitForSubscriptions = function (pause) {
if (this.ready()) { //all the subs have come in
//NProgress.done();
setPlan(this.params._id);
} else { //all subscriptions aren't yet ready, keep waiting
//NProgress.start();
pause();
}
};
Router.map(function () {
this.route('calendar', {
path: '/calendar/:_id',
template: 'calendar',
before: [
subscribeAllPlanItems,
waitForSubscriptions
],
});
//Other routes omitted
});
var requireLogin = function (pause) {
if (Meteor.loggingIn()) { //still logging in
pause();
}
if (!Meteor.user()) { //not logged in
this.render('signIn');
pause();
} else { //logged in, life is good
console.log("requireLogin: logged in");
}
};
//This enforces login for all pages except the below ones.
Router.before(requireLogin, {
except: ['landing', 'signUp', 'signIn', 'forgotPassword', 'resetPassword']
});
I opened an issue on Github about this. Here's the response I got:
Oops I may have not changed the redirect method yet. Just use Router.go as it will work fine now. I will change over this.redirect sometime next week or a PR is welcome. Controllers are now automatically stopped if you change routes in a hook. You can pause the current run by calling the pause method which is passed as a parameter to your hooks and action functions.

building jQuery plugIn

I'm building an easy plugIn for validations, after setting up some options to be editable,
and after cycling all the fields i wrote:
$(this).submit(function () {
where "this" is the main element (the form).
Now I was wondering to use this plug-in in asp.net as well, so without using an html form, where there are just some inputs into a div and on click on a specific button it start...
So I know that here I have to change the submit... and trying to bind it on click of the button... I don't know how to solve this...
Can someone help?
You need help to bind a click event? For that you write
$('#buttonID').click(function(e)
{
// do some logic
e.preventDefault(); // make sure that ie. a href is not followed
});
you should take a look at what I was doing here. My plugin hijacks a form post to submit data cross domain to my server instead of the hosting server. The overall method could be used for your validation.
here's a quick and dirty example of my code.
$.fn.myplugin= function (options) {
var settings = {
setting1: undefined,
setting2: undefined,
setting3: undefined,
beforeSubmit: function () { return true; },
afterSubmit: function () { },
approve: function () { },
decline: function () { },
error: function () { },
exception: function (xhr, status, error) { }
};
// If options exist, lets merge them
// with our default settings
if (options) {
$.extend(settings, options);
}
//ensure this is attached only to a FORM element
if (!$(this).is("form"))
throw ('Specified object is not a valid form. This plugin can only be attached to a form element.');
$(this).live("submit", function (event) {
var result = true;
//NEVER EVER EVER allow the form to submit to the server
event.preventDefault();
if (settings.beforeSubmit)
result = settings.beforeSubmit();
if (result != null && !result)
return false;
//do stuff
}); //end live submit
};
Then, usage looks like this
$('#form-id').myplugin({
setting1: 'value',
setting2: 'value',
setting3: 'value'
});

Resources