How can I route to a users profile page? - meteor

I show a list of items and for each item its belongs to a user. I list the item's name, description and the user who created it (by there name). I want to also have a link that goes to the user who created the item. Note: That I also link to an item's page.
Here is what I've done so far:
packages
aldeed:collection2
aldeed:simple-schema
iron:router
aldeed:autoform
useraccounts:iron-routing
accounts-password
accounts-base
useraccounts:core
zimme:active-route
todda00:friendly-slugs
reywood:publish-composite
client/items/listed_item.html
<template name="listedItem">
<a href="{{pathFor 'itemPage'}}">
{{name}}
</a>
<a href="{{pathFor 'profile'}}">
{{usernameFromId user}}
</a>
</template>
client/items/items.html
<template name="items">
<div class="items">
{{#each items}}
{{> listedItem}}
{{/each}}
</div>
</template>
client/subscriptions.js
Meteor.subscribe('items');
Meteor.subscribe('allUsernames');
Meteor.subscribe('users');
client/helpers.js
Template.items.helpers({
items: function() {
return Items.find();
},
});
Template.registerHelper("usernameFromId", function (userId) {
var user = Meteor.users.findOne({_id: this.userId});
return user.profile.name;
});
server/publications.js
Meteor.publish("items", function () {
return Items.find();
});
Meteor.publish("users", function () {
return Meteor.users.find({}, {
fields: { profile: 1 }
});
});
Meteor.publish("allUsernames", function () {
return Meteor.users.find({}, {
fields: { 'profile.name': 1, 'services.github.username': 1 }
});
});
lib/routes.js
Router.route('/items', function () {
this.render('items');
});
Router.route('/users/:_id', {
template: 'profile',
name: 'profile',
data: function() {
return Meteor.users.findOne({_id: this.params._id});
}
});
What this does though is show the items URL for the users URL, so it links to a user who doesn't exist. i.e. items/1234 = users/1234 when theres only users/1 in the system. How can I get it to link to the correct user ID?

use a link with the constructed URL
<template name="listedItem">
<a href="{{pathFor 'itemPage'}}">
{{name}}
</a>
<a href="http://yourdomain.com/users/{{user}}">
{{usernameFromId user}}
</a>
</template>

In this part:
Router.route('/users/:_id', {
template: 'profile',
name: 'profile',
data: function() {
return Meteor.users.findOne({_id: this.params._id});
}
});
you have referenced the route and created a route to a template with the name "profile" but I can't see any template with that name. Is it possible you just forgot to include it here? or that you really don't have that template?
Just making sure.

Try this:
Router.route('/users/:_id', {
template: 'profile',
name: 'profile'
}
In helper you can retrive that record id by this:
Router.current().params._id

I usually use this way:
In the template:
<div class="css-light-border">
{{title}}
</div><!-- / class light-border -->
In the router.js file:
Router.route('/document/:_id', function(){
Session.set('docid', this.params._id);
this.render('navbar', {to: "header"});
this.render('docItem', {to: "main"});
});
Basically here docid is the _id of the document which I want to display. Here is an example of how you pull from your database:
somehelper:function(){
var currentId = Session.get('docid');
var product = Products.findOne({_id:currentId});
return product;
I think it is an easy way because it uses Sessions.

Related

Can't send data context to template via Iron Router in Meteor

This is my router:
Router.route('/cource/:courcePath', {
name: 'Cource_page',
template: 'Cource_page',
data() {
return Cources.find({ courcePath: this.params.courcePath });
}
});
Template:
<template name="Cource_page">
<div class="container">
{{#each cources}}
<h1>{{courceTitle}}</h1>
{{/each}}
</div>
</template>
And helper:
Template.Cource_page.helpers({
cources() {
let courcePath = this.courcePath;
console.log(courcePath);
return Cources.find({ courcePath: courcePath });
}
});
When I go to some page (http://localhost:3000/cource/my-new-cource, for example), no data rendering and I get undefined in the console (the output of template helpers). What am I doing wrong?
You need to pass the data in the render directive
Router.route('/post/:_id', function () {
this.render('Post', {
data: function () {
return Posts.findOne({_id: this.params._id});
}
});
});
OR
you should subscribe to the data in the route:
Router.route('/cource/:courcePath', {
name: 'Cource_page',
template: 'Cource_page',
subscriptions: function() {
this.subscribe('courses', this.params.courcePath);
}
});
Check the guide for more info:
http://iron-meteor.github.io/iron-router/
When you provide the data context in your i-r route you don't need the helper. Try:
Router.route('/cource/:courcePath', {
name: 'Cource_page',
template: 'Cource_page',
data() {
return Cources.find({ courcePath: this.params.courcePath });
}
});
<template name="Cource_page">
<div class="container">
{{#each this}}
<h1>{{courceTitle}}</h1>
{{/each}}
</div>
</template>

Meteor : create a search (filter) without using autopublish

I have a search facility in my project and I need to be able to publish results without using autopublish.
html
<template name="search">
<form id="searchform">
<input type="text" id="kategori" placeholder="Sila masukkan maklumat carian."/>
<button>Carian</button>
</form>
<hr/>
<h3>Maklumat</h3>
<ol>
{{#each profil}}
<li>{{jenama}}</li>
{{/each}}
</ol>
</template>
js:
Template.search.events({
"submit #searchform": function (e) {
e.preventDefault();
Session.set("kategori", e.target.text.value);
}
});
Template.search.helpers({
profil: function() {
return Profil.find({
kategori: Session.get('kategori'),
});
}
});
You can simply subscribe to a filtered publication:
client:
Template.search.events({
"submit #searchform": function (e) {
e.preventDefault();
Session.set("kategori", e.target.text.value);
Meteor.subscribe('profiles',Session.get('kategori'));
}
});
server:
Meteor.publish('profiles',function(kategori){
return Profil.find({ kategori: kategori });
});
If you don't have any other subscriptions to the same collection you can also simplify your helper to:
Template.search.helpers({
profil: function() {
return Profil.find();
}
});
Since the set of documents will be defined by your publication.
In practice though you usually use the same search in your helper as you do in the publication just to avoid documents from other publications showing up.

iron:router will not re-render after route change with same template

How can I make Iron:router re-render a template?
I have this html:
<head>
</head>
<body>
</body>
<template name="mainLayout">
list
find
{{> yield}}
</template>
<template name="listTemplate">
<p>list</p>
</template>
and this js:
Router.configure({
layoutTemplate: 'mainLayout'
});
Router.route('/list', {
name: 'list',
template: 'listTemplate'
});
Router.route('/find', {
name: 'find',
template: 'listTemplate',
data: function () {
return this.params.query;
}
});
if (Meteor.isClient) {
Template.listTemplate.rendered = function () {
if (this.data)
console.log('find ' + this.data.q);
else
console.log('list all');
};
}
When I click on the links to switch views (simulated here with console.log), the route does change, but the template is not re-rendered.
Is there a way to force iron:router to re-render?
Setting the router controller state did not work for me. The answer Antônio Augusto Morais gave in this related github issue worked. Using the Session to store the reactive var to trigger the autorun reactiveness. It's a hack, but it works.
## router.coffee
Router.route '/profile/:_id',
name: 'profile'
action: ->
Session.set 'profileId', #params._id
#render 'profile'
## profile.coffee
Template.profile.onCreated ->
#user = new ReactiveVar
template = #
#autorun ->
template.subscription = template.subscribe 'profile', Session.get 'profileId'
if template.subscription.ready()
template.user.set Meteor.users.findOne _id: Session.get 'profileId'
else
console.log 'Profile subscription is not ready'
Template.profile.helpers
user: -> Template.instance().user.get()
## profile.html
<template name="profile">
{{#if user}}
{{#with user.profile}}
<span class="first-name">{{firstName}}</span>
<span class="last-name">{{lastName}}</span>
{{/with}}
{{else}}
<span class="warning">User not found.</span>
{{/if}}
</template>
You can try something like this:
Router.configure({
layoutTemplate: 'mainLayout'
});
Router.route('/list', {
name: 'list',
template: 'listTemplate',
action: function() {
this.state.set('query', this.params.query);
}
});
Router.route('/find', {
name: 'find',
template: 'listTemplate',
data: function() {
return this.params.query;
},
action: function() {
this.state.set('query', this.params.query);
}
});
if (Meteor.isClient) {
Template.listTemplate.rendered = function() {
this.autorun(
function() {
if (this.state.get('query'))
console.log('find ' + this.data.q);
else
console.log('list all');
}
);
};
}
The rendered method isn't reactive, that's why you need an autorun.
The template "this.data" isn't reactive so you're gonna need a reactive var to do that, either a Session variable, a controller state, or some kind of reactive var.
You may need to add the reactive-var package depending on what approach you take.

Meteor and Iron Router: raise 404 when id doesn't exist

I'm using Iron Router for my urls and I have this route:
this.route('regionEdit', {
path: '/region/:_id',
waitOn: function() {
return Meteor.subscribe('region', this.params._id);
},
data: function() {
return Regions.findOne({
_id: this.params._id
});
}
});
This works fine when I use this path http://example.com/region/xgok3Etc5mfhtmD7j
Where xgok3Etc5mfhtmD7j is the _id of region. However, when I access to http://example.com/region/whatever, the page renders normally, but without data.
How can I raise a 404 error for this?
not a 404, but you can render a not found page by doing something like this.
this.route('regionEdit', {
path: '/region/:_id',
waitOn: function() {
return Meteor.subscribe('region', this.params._id);
},
data: function() {
var region = Regions.findOne({
_id: this.params._id
});
if(!region)
this.render("notFound");
else
return region;
}
});
I think you can try Plugins
According to this documentation there is already a built in plugin for this issue
Router.plugin('dataNotFound', {notFoundTemplate: 'notFound'});
And it is described as
This out-of-box plugin will automatically render the template named "notFound" if the route's data is falsey
In router.js
Router.configure({
layoutTemplate:'layout',
notFoundTemplate: 'notFound'
});
Configure your router this way to solve the issue
and Template Part
<template name="notFound">
<div class="container">
<h1 class="colorWhite">Oopss..ss..ss..</h1>
<p class="colorWhite">You are out of the world, let's go back</p>
</div>
</template>
make it like this.. it should work, in fact, it works for me..
I include a catch all route on my Router.map:
router.js
Router.map(function() {
... // other routes
this.route('404', {
path: '/*',
layoutTemplate: 'application', // this actually lives in Router.configure();
template: 'pageNotFound',
onBeforeAction: function(){
console.log('not found');
}
});
});
templates.html
<template name="pageNotFound">
<div>
<h2>404 - page not found</h2>
</div>
</template>
<template name="application">
<div>
<h1>My Application</h1>
{{> yield}}
</div>
</template>
This pageNotFound template then gets rendered in the {{> yeild}} partial of the application template if none of the other routes pick up the uri path.

Iterating through an array in a Meteor.js collection

Background: writing a web application using Meteor.js where users can add board games to their profile. There is a Users collection and a Games collection.
I have the list of Games and each game has a button next to it so the user can add the game to their profile. The button will find the _id of each game and add it to a user.games array. The _id is a really long hash.
On the user's dashboard, I want to be able to display each game the user has "subscribed" to but I'm not sure how to access the user.games field.
Here is my code:
/server/publications.js
Meteor.publish('userGames', function () {
return Meteor.users.find({_id: this.userId},
{fields: {'games': 1}});
});
/client/main.js
Meteor.subscribe('userGames');
/client/views/dashboard/dashboard.html
<template name="dashboard">
<div class="dashboard">
{{#if hasGames}}
<ul class="games-list">
{{#each userGames}}
{{> game}}
{{/each}}
</ul>
{{else}}
<h3>You have not added any games to your chest</h3>
{{/if}}
</div>
</template>
/client/views/dashboard/dashboard.js
Template.dashboard.helpers({
hasGames: function(){
},
userGames: function(){
}
});
As you can see I'm not sure what goes into the dashboard.js helper function in order to be able to access the user.games field.
EDIT:
So I ran a test to see if the below answer works - I've updated the following:
dashboard.html
<template name="dashboard">
<div class="dashboard">
{{test}}
</div>
</template>
dashboard.js
Template.dashboard.helpers({
test: function(){
var user = Meteor.user();
return Games.find({_id: { $in: user.games }});
}
});
The console says "Uncaught TypeError: Cannot read property 'games' of undefined"
Finding all games for currently logged user
Games = new Meteor.Collection("userGames");
if (Meteor.isClient) {
Meteor.subscribe('userGames');
Template.hello.greeting = function () {
var user = Meteor.user();
if(user && Array.isArray(user.games)){
return Games.find({_id: { $in: user.games }}).fetch();
}else{
return [];
}
};
}
if (Meteor.isServer) {
Meteor.publish('userGames', function () {
return Meteor.users.find({_id: this.userId},
{fields: {'games': 1}});
});
}

Resources