4
votes

I would like to group posts by date, using Meteor, and still retain its characteristic reactivity. I don't know it that is really possible.

I am developing a website based on the Microscope, following the instructions from the book Discover Meteor, but I'm having a hard time making small changes, because I do not have experience with Meteor.

I made small adjustments to the original code book, but nothing that really change its original structure.

What I need to do is group posts by date so they look like this:

  • Today
    • Post 7
    • Post 6
    • Post 5
  • Yesterday
    • Post 4
    • Post 3
  • 08/11/2014
    • Post 2
    • Post 1

My current code is structured as follows:

/client/view/posts/posts_list.js

Template.postsList.helpers({    
    posts: function() {
        return Posts.find({}, {sort: {submittedDate: -1}});
    }
});

/client/view/posts/posts_list.html

<template name="postsList">
    <div class="posts">
        {{#each posts}}
            {{> postItem}}  
        {{/each}}
        {{#if nextPath}}
            <a class="load-more" href="{{nextPath}}">Show more</a>
        {{/if}}
    </div>
</template>

/client/view/posts/post_item.js

Template.postItem.helpers({
    ownPost: function () {
        return this.userId == Meteor.userId();
    },
});

/client/view/posts/post_item.html

<template name="postItem">
    <div class="post">
        <div class="post-content">
            <h3><a href="{{url}}">{{title}}</a><span>{{description}}</span></h3>
        </div>
        <div class="post-comments">
            <a href="{{pathFor 'postPage'}}">{{commentsCount}} comments</a>
        </div>
        {{#if ownPost}} 
            <a href="{{pathFor 'postEdit'}}">Edit</a>
        {{/if}}     
    </div>
</template>

/collections/posts.js

Posts = new Meteor.Collection('posts');  
Posts.allow({
    update: ownsDocument,
    remove: ownsDocument
});

Meteor.methods({
    post: function(postAttributes) {
        var user = Meteor.user(), postWithSameLink = Posts.findOne({url: postAttributes.url});
        if(!user)
        throw new Meteor.Error(401, "You need to be a registered user to do this");
        if(!postAttributes.title)
            throw new Meteor.Error(422, "Please, fill the name field");
        if(!postAttributes.description)
            throw new Meteor.Error(422, "Please, fill the description field");
        if(!postAttributes.url)
            throw new Meteor.Error(422, "Please, fill the URL field");
            if(postAttributes.url && postWithSameLink) {
            throw new Meteor.Error(302, "This URL already exist", postWithSameLink._id);
        }

        var post = _.extend(_.pick(postAttributes, 'url', 'title', 'description'), {
            userId: user._id,
            author: user.username,
            submittedDate: new Date().getTime(),
            commentsCount: 0
        });     

        var postId = Posts.insert(post);
        return postId;
    }
});

/server/publications.js

Meteor.publish('posts', function(options) {
    return Posts.find({}, options);
});

Meteor.publish('singlePost', function(id) {
    return id && Posts.find(id);
});

Meteor.publish('comments', function(postId) {
    return Comments.find({postId: postId});
});

Meteor.publish('notifications', function() {
    return Notifications.find({userId: this.userId});
});

I tried several solutions I found here and on GitHub, but I could not make any of them work. The solutions I tried were these:

StackOverflow 1 (Meteor Issue 644): Are "group by" aggregation queries possible in Meteor, yet?

GitHub Arunoda's Approach: https://github.com/arunoda/meteor-smart-collections/issues/47

Also, I've tried to use the list-grouper (atmosphere package), but was not able to implement the package's instructions in my code.

If any good soul here knows how to do this, I would greatly appreciate it. Very, very much! :)

2
Hi! I wrote the list-grouper package, and can probably show you how to use it, but I'm not currently at a computer. I'll get back to you. - Kristoffer K
ok. Thanks @KristofferK. I would appreciate that! :) - Deivide Oliveira

2 Answers

0
votes

I did not find a 'submittedDate' property on the meteor document object. It may be necessary that when you insert a new document (entry) to your DB, that you specify current date/time as one of the parameters to go along with the rest.

0
votes

There's more code there than's needed for dealing with your core question, I think. I've simplified a bit -- hopefully this helps. I'll just note I'm not an expert -- also learning. I haven't had time to test this. But I think it addresses a way of accomplishing what you need.

I think the basic structure of the template would look something like this.

<ul>
    {{#each post}}
        {{if isNewDate}}
            <ul>
               <li>{{writeDate}}</li>
            </ul>
        {{/if}}
        <li>{{postName}}</li>
    {{/each}}
</ul>

The helpers.js file could look something like this, I think.

var tempDate = {}; //we need a variable outside the scope of the helper functions 
Template.foobar.helpers ({
    post: function(){
        Posts.find({}, {sort: {submittedDate: -1}}); 
    },
    isNewDate: function(){
        //test if the date of this record matches the date of the previous record
        //if it's new, return true.
        //see momentJS -- makes dealing with dates sooooo much easier
        if( moment().format("LL", this.submittedDate) !== moment().format("LL", tempDate)){
            tempDate = this.submittedDate;
            return true;
        } else {
            return false;
        }
    },
    writeDate: function(){
        return moment().format("LL", this.timestamp);
    }
})