Meteor - Passing an object to template but it doesnt display data - javascript

Im trying to create a blog(with meteor) that will have different categories for posts, then trying to create a page that displays all categories and the titles off posts in those categories.
This is the Javascript code I am using.
Template.categories.cats = function(){
reviews = Reviews.find({}, {sort: { createdAt: -1 } });
opinions = PointlessOpinions.find({}, {sort: { createdAt: -1 } });
days = DaysInTheLife.find({}, {sort: { createdAt: -1 } });
return {reviews: reviews,opinions: opinions, days: days};
}
This is the HTML template
<template name = "categories">
<div class = "container">
<h1>Reviews</h1>
{{#each reviews}}
<h2> {{title}}</h2>
{{/each}}
</div>
<div class = "container">
<h1>A day in the life</h1>
{{#each days}}
<a href="/post/{{this._id}}">
<h2> {{title}}</h2>
</a>
{{/each}}
</div>
<div class = "container">
<h1>Pointless Opinions</h1>
{{#each opinions}}
<a href="/post/{{this._id}}">
<h2> {{title}}</h2>
</a>
{{/each}}
</div>
</template>
I have tested to see if the Collections have the data and it seems so

You should write it like this:
Template.categories.helpers({
reviews: function (){
return Reviews.find({}, {sort: { createdAt: -1 } });
},
//and the rest of the helpers to use in that template
});

Luna is correct and you should not do .fetch() as Ramil suggested. You are allowed to return a cursor from a helper and you should do so as it is more performant than returning an Array.

Related

Saved an object's id in a Meteor.user field, recalled the id in a template, how can i display the object's data instead of the id?

I have a collection of objects called Categories in a list. in my html, each category object is a list item and this category object has other objects in it, these are the category id, name and an array of posts that belong to that category. see image.
On each Category list item is a button that the user can click, this then saves the category id in a Meteor.user field called name.
<template name="CategoriesMain">
<ul>
{{#each articles}}
<li>
<h2>{{name}}</h2>
<button type="button" class="toggle-category">Add to User Field</button>
</li>
{{/each}}
</ul>
</template>
to achieve this i have this in my helper
Template.CategoriesMain.events({
'click .toggle-category': function(e){
//take the category id on click
var ob = this._id;
//make it into array
var id = $.makeArray( ob );
e.preventDefault();
Meteor.call('addingCategory', id, function(error, user){ console.log(id)});
},
});
then in my methods.
Meteor.methods({
addingCategory: function(name) {
Meteor.users.update({
_id: Meteor.userId()
},
{
$addToSet: {
name: name
}
});
}
});
Each user has a timeline in which the saved category ids appear.
<template name="userTimeline">
{{#if currentUser}}
<div class="timeline-user">
<p>{{name}}</p>
</div>
{{/if}}
</template>
in the helper
Template.userTimeline.helpers({
name: function() {
return Meteor.user().name;
//this is what im experiment with to link the category id's in the timeline with the category ids from the Category collection but i'm not sure if im going the right direction.
var name = FlowRouter.getParam('_id')
return CategoryCollection.find({_id: id}).fetch();
}
});
My question is, instead of displaying the category ids, can somehow get the objects of those category id and i.e posts that belong in that category? i know i have to somehow link the id collected by the user with that of the category
EDIT
I have amended my meteor methods to declare "category" as an array like so:
Accounts.onCreateUser(function(options, user){
user.category = [];
return user;
});
Meteor.methods({
addingCategory: function(category) {
console.log(Meteor.userId());
Meteor.users.update({
_id: Meteor.userId()
},
{
$addToSet: {
category: category
}
});
}
});
this is what the Meteor.users looks like, take a look at the "category" field.
I have amended the following in my helper, which is throwing the error:
Template.userTimeline.helpers({
category(){
return CategoryCollection.find({ _id: { $in: this.category }}); // a cursor of categories
}
});
in which CategoryCollection is the collection holding the categories.
since i declared "category" as an array in my methods, i'm no longer changing each category id into an array as i was doing before, so i changed my template event to this.
Template.CategoriesMain.events({
'click .toggle-category': function(e){
var ob = this._id;
console.log(ob);
e.preventDefault();
Meteor.call('addingCategory', ob, function(error, user){ console.log(ob)});
}
});
my Publish has changed to this: i don't know whether here i should use $in ?
Meteor.publish(null, function() {
return Meteor.users.find({_id: this.userId}, {fields: {category: 1}});
});
my html has been changed to this:
<template name="userTimeline">
{{#if currentUser}}
<div class="timeline-user">
{{#each category}}
Count: {{count}}
Description: {{description}}
Link: {{link}}
{{#each posts}}
ID: {{id}}
Title: {{title}}
{{/each}}
{{/each}}
</div>
{{/if}}
</template>
You can show the categories related to a user by iterating over the array of category ids and using a helper to return the entire category object. Then inside that you can loop over the posts.
<template name="userTimeline">
{{#if currentUser}}
<div class="timeline-user">
{{#each categories}}
Count: {{count}}
Description: {{description}}
Link: {{link}}
{{#each posts}}
ID: {{id}}
Title" {{title}}
{{/each}}
{{/each}
</div>
{{/if}}
</template>
Then your helper:
template.userTimeline.helpers({
categories(){
if ( this.category &&
typeof(this.category) === "object" &&
this.category.length ){ // check to see if the list of categories is an array
return categories.find({ _id: { $in: this.category }}); // a cursor of categories
} else {
console.log(this.category);
return null;
}
}
});
Remember that the data context this for the userTimeline template is the Meteor.user() object so this.name is going to be the array of category ids in Meteor.user().name

Return All Meteor Users Except The Current User?

I have a page that displays all the registered users, but wanted to omit the current user. Is there a way to return all Meteor's users except the current user.
Here is my html:
<template name="users">
<div class="contentDiv">
<div class="blueTop pageContent" id="profileName">Users</div>
{{#each users}}
<div class="pageContent text">
<a class="user link" id="{{_id}}">{{profile.firstName}} {{profile.lastName}}</a>
<button class="addFriend">Add Friend</button>
</div>
{{/each}}
</div>
</div>
</template>
And my javascript:
if (Meteor.isClient) {
Meteor.subscribe("users");
Template.users.helpers({
users:function(){
return Meteor.users.find({}, {sort: {firstName: -1}}).fetch();
}
});
}
if (Meteor.isServer) {
Meteor.publish("users",function(){
return Meteor.users.find();
});
}
You could use the comparison query operator $ne to filter out documents which are not equal to a specified value, in your case Meteor.userId().
For example:
Meteor.users.find({_id: {$ne: Meteor.userId()}});
If you are using a publication, you can simply use the $ne operator. this.userId is set on all publication functions as the current user.
Meteor.publish('all_users', function () {
return Meteor.users.find({
_id: { $ne: this.userId }
});
});

Meteor dynamic category list

I would like to do the following. I would like to create a categories page that loads each category onto a picture. Then when a user clicks a category the parameter would show up on the url and it will search the database for photos based on that category. I will now demonstrate the code that I have.
Categories HTML File:
<template name="categories">
<div class="text-center light-container" id="categories-section">
<h1>Categories</h1>
<hr/>
{{#each categories}}
<div class="image-container">
<a href="{{pathFor route='categoryPage'}}">
<img class="freezeframe pics" src="images/app/sphere.jpg"/>
</a>
<h2><span>{{categories}}</span></h2>
</div>
{{/each}}
</div>
</template>
Categories JS File:
var categoryList = ['actions', 'animals', 'anime', 'art/design', 'cartoons/comics', 'celebrities',
'Emotions', 'Food/Drink', 'Games', 'History', 'Holidays', 'Memes', 'Movies', 'Music', 'Nature', 'News/Politics',
'Science', 'Sports', 'Technology', 'TV'];
Template.categories.helpers({
'categories':function(){
for(var i = 0; i < categoryList.length; i++){
console.log(categoryList[i]);
return categoryList[i];
}
}
});
Router JS File:
Router.route('/categories', {
name: 'categories',
template: 'categories',
fastRender: true
});
Router.route('/categories/:category', {
name: 'categoryPage',
template: 'categoryPage',
data: function(){
var category = this.params.category;
return GifsCollection.find({category: category});
},
fastRender: true
});
CategoryPage JS:
Template.categoryPage.helpers({
// Load 16 most recent ones
// When down arrow is click load another 16 more gifs
gifs: function() {
var category = this.params.category;
return GifsCollection.find({category: category}, {fields: {_id: 1, image: 1} });
}
});
Running the following code doesn't get me anywhere. I'm not sure which path to take. I can create a 'category' collection and load the helpers onto there or I can use sessions? but I'm leaning onto creating category collection however I'm pretty sure there is a much more efficient way.
Any feedback and code help would be greatly appreciated!!!
You have two small errors. One we already discussed in comments, regarding the helper. The other is in how you use the #each loop: inside of it you can just refer to this to get the string of your category.
Categories HTML File:
<template name="categories">
<div class="text-center light-container" id="categories-section">
<h1>Categories</h1>
<hr/>
{{#each categories}}
<div class="image-container">
<a href="/categories/{{this}}">
<img class="freezeframe pics" src="images/app/sphere.jpg"/>
</a>
<h2><span>{{this}}</span></h2>
</div>
{{/each}}
</div>
</template>
Categories JS File:
var categoryList = ['actions', 'animals', 'anime', 'art/design', 'cartoons/comics', 'celebrities',
'Emotions', 'Food/Drink', 'Games', 'History', 'Holidays', 'Memes', 'Movies', 'Music', 'Nature', 'News/Politics',
'Science', 'Sports', 'Technology', 'TV'];
Template.categories.helpers({
'categories':function(){
return categoryList;
}
});

How to build comment system in ember.js

I am fairly a newbie to ember.js. I currently working on a school project which is essentially a message board (forum) application that allows users to add posts with comments.
My application contains three models: courses, messages, comments
course->hasMany->messages->hasMany->comments
So far I have been able to view all the courses and related messages using filter query to my server. Adding new messages works fine also except that it is not updating the new message added to the screen.
Problem: It is only when I refresh the page the new message I added is displayed.
App.Router.map(function() {
this.resource('home', { path : '/'}, function() {
this.resource('mycourse', { path : ':course_id' } );
});
});
App.MycourseRoute = Ember.Route.extend({
model: function(params) {
// the model for this route is a new empty Ember.Object
var string = '{"filters":[{"name":"courseid","op":"eq","val":'+params.course_id+'}]}'
return this.store.find('message', { q: string });
}
});
App.HomeRoute = Ember.Route.extend(
{
model: function() {
return this.store.find('course');
}
});
Here is my message controller:
App.MycourseController = Ember.ArrayController.extend({
actions: {
addMessage: function(messageText) {
var message = messageText;
var messageAdd =this.store.createRecord('message', {
message: message,
posttime: "12:00pm",
courseid: 4,
userid: 1
});
messageAdd.save();
}
}
});
My html part:
<script type="text/x-handlebars" id="home">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
{{#each}}
<li>{{#link-to 'mycourse' this.id}}{{name}}{{/link-to}}</li>
{{/each}}
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">Subscribed Courses:</h1>
{{outlet}}
</div>
</div>
</script>
<script type="text/x-handlebars" id="mycourse">
<button class="btn btn-default" type="button" id="create-message" {{action "addMessage" messageTxt}}>
Post!
</button>
{{input type="text" value=messageTxt}}
<br><br>
{{#each}}
<b>{{message}}</b>
<li>{{posttime}}</li>
<li>User name: {{user.username}}</li>
<li>Course name: {{course.alt_name}}</li>
<h4>Comments:</h4>
{{#each comments}}
<li>{{comment}}</li>
{{/each}}
<br>
{{/each}}
</script>
Turns out when you use findQuery (which I believe is the same as using find with query parameters), Ember does not return a live updating array, whereas it does for a straight up find/findAll. See this question on that exact issue that I asked a while back.
The solution here (adapted from kingpin2k's answer to said question) is to use filter to trick Ember into auto-updating:
App.MycourseRoute = Ember.Route.extend({
model: function(params) {
// the model for this route is a new empty Ember.Object
var string = '{"filters":[{"name":"courseid","op":"eq","val":'+params.course_id+'}]}'
return this.store.find('message', { q: string });
},
setupController:function(controller, model){
var filter = this.store.filter('color', function(color){
return model.contains(color);
});
this._super(controller, filter);
}
});

Ember multiple Json request Error while loading route Object has no method 'addArrayObserver'

im having a problem with my ember app. Im new to it, and trying to do something fun. So the idea of this app is to go and fetch a list of artists from a server via an ajax call, and then if you click the artist it will go to the server again and fetch the albums via another ajax call.
So the first part is working, it is actually fetching the artists through the ajax call when i click on "music library", but then when clicking on the artist it throws the following error:
Assertion failed: Error while loading route: TypeError: Object [object Object] has no method 'addArrayObserver'
I've read so many different options, and i think im on the right track because by printing on the console i can see that it is actually going to the server and fetching the right artist's albums, but the error is throw at the last moment, so it is not displaying the albums. I was also able to show the albums when reloading or typing the url (not now, since i changed the code to implement the afterModel)
So, here is my code:
App = Ember.Application.create({
LOG_TRANSITIONS: true,
LOG_TRANSITIONS_INTERNAL: true
});
App.Library = Ember.Object.extend({
name: null,
artist: []
});
App.Library.reopenClass({
loadArtist: function() {
var artistList = Em.A();
$.getJSON('url').then(function(data){
//json parsing, creating a library object and putting it into the array
});
return artistList;
}
});
App.Artist = Ember.Object.extend({
id: null,
name: null,
coverArt: null,
albumCount: null
});
App.Albums = Ember.Object.extend({
albums: []
});
App.Artist.reopenClass({
loadAlbums: function(params) {
var albumsJson = 'url' + params.artist_id +'';
var albumList = Em.A();
$.getJSON(albumsJson).then(function(data){
//parsing json, creating artist objects and pushing them into the array
});
return albumList;
//});
}
});
/*****************************ROUTER**************************************************************************************/
App.Router.map(function() {
// put your routes here
this.resource('library', function() {
this.resource('artist', { path: '/:artist_id'});
});
});
App.IndexRoute = Ember.Route.extend({
model: function() {
var hi = ['Welcome'];
return hi;
}
});
App.LibraryRoute = Ember.Route.extend({
model: function() {
return App.Library.loadArtist();
}
});
App.ArtistRoute = Ember.Route.extend({
model: function(params) {
this.transitionTo('artist', params);
},
afterModel: function(params, transition){
var artist = Em.A();
if(params.artist_id==null){
artist.push(App.Artist.create({artist_id: params.id}));
} else {
artist.push(App.Artist.create({artist_id: params.artist_id}));
}
return App.Artist.loadAlbums(artist[0]);
}
});
/**************************************CONTROLLERS***********************************************************************************/
App.ArtistController = Ember.ArrayController.extend({
needs: "library"
});
App.LibraryController = Ember.ArrayController.extend({});
I would really appreciate some help!
Also, the HTML is as follows:
<script type="text/x-handlebars">
<div class="navbar navbar-default">
<div class="navbar-inner">
<a class="navbar-brand" href="#">My Library</a>
<ul class="nav navbar-nav">
<li>{{#linkTo 'index'}}Home{{/linkTo}}</li>
<li>{{#linkTo 'library'}}Music Library{{/linkTo}}</li>
</ul>
</div>
</div>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
<div class="container">
{{#each item in model}}
<h1>{{item}}</h1>
{{/each}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="library">
<div class="container">
<div class="row">
<div class="col-md-4">
<table class="table">
{{#each model}}
<tr><td>
{{name}}
</td></tr>
{{#each artist}}
<tr><td>
{{#linkTo 'artist' this}}
{{name}}
{{/linkTo}}
<!--<a {{action 'selectArtist' this}}> {{name}} </a>-->
</td></tr>
{{/each}}
{{/each}}
</table>
</div>
<div class="col-md-8">
<p>Albumes</p>
{{outlet}}
</div>
</div>
</div>
</script>
<script type="text/x-handlebars" data-template-name="artist">
<div class="container">
<div class="col-md-4">
<table class="table">
<tr><td><p>{{controllers.library.artist.name}}</p></td></tr>
{{#each itemController='album'}}
<tr><td>
{{{name}}}
</td></tr>
{{/each}}
</table>
</div>
</div>
</script>
Thanks a lot!!
To get rid of the error you need to modify the model function of the App.ArtistRoute, to return an array as App.ArtistController is an Ember.ArrayController.
For example,
App.ArtistRoute = Ember.Route.extend({
model: function(params) {
//this.transitionTo('artist', params);
return [];
},
....
Or even place the code of afterModel function in model function to retrieve the albums of this artist.
Although i'm not certain if you really want the model of your artist context to be the albums, it does not look correct to me. I would suggest to make the App.ArtistController aν Ember.ObjectController, assign the model to an App.Artist object and store the albums related to this artist in a property of the App.Artist class. In that case you will need to add a property in App.Artist and create a class of App.Album.
With this in mind have a look at the following example which is a very rough modification of your code (caution the App.ArtistController has not been switched instead its model is an array of albums),
http://emberjs.jsbin.com/AdOfiyiN/2#/library/2
OK, i solved it using this question:
Why isn't my ember.js route model being called?
Instead of putting the logic in the model or afterModel, i just needed to set the controller.
Hope it helps to someone.
Best!

Categories