Grouping by date using Meteor - javascript

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>{{title}}<span>{{description}}</span></h3>
</div>
<div class="post-comments">
{{commentsCount}} comments
</div>
{{#if ownPost}}
Edit
{{/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! :)

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.

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);
}
})

Related

metalsmith-collections via gulpsmith not generating an array of my collection

So, this is admittedly a niche question. It has to do with metalsmith-collections via gulpsmith.
I'm adding a blog to a static site and using metalsmith via gulpsmith to do so.
I'm having trouble using metalsmith-collections with this setup, though it seems like everything should be working fine.
I'll attempt to show my relevant code.
Here's my (I think) relevant required modules:
var gulp = require('gulp');
var metalsmith = require('metalsmith');
var gulpsmith = require('gulpsmith');
var markdown = require('metalsmith-markdown');
var collections = require('metalsmith-collections');
I have a gulp 'blog' task that otherwise works as expected.
gulp.task('blog', function() {
return gulp
.src(blogInput)
.pipe(gulp_front_matter()).on("data", function(file) {
assign(file, file.frontMatter);
delete file.frontMatter;
})
.pipe(
gulpsmith()
.use(collections({
posts: {
pattern: '/src/blog/*.md',
sortBy: 'date',
reverse: true
}
}))
)
.pipe(gulp.dest(blogOutput))
});
I want to output a list of my latest blog posts.
So, my hbs template is as follows:
<article>
<ul>
{{#each collections.posts}}
<li>
<h3>{{this.title}}</h3>
<article>{{this.contents}}</article>
</li>
{{/each}}
</ul>
The problem code is apparently above:
{{#each collections.posts}}
Nothing gets output there.
Well, technically, the output is this:
<article>
<ul>
</ul>
</article>
No iterating through the array of posts that is supposed to be generated.
Not sure if this is all the relevant code, but I'm happy to add more for any help troubleshooting.
Any suggestions greatly appreciated.
UPDATE
var blogInput = './src/blog/*.md';
var blogOutput = './blog/';

Ember.js route problems with filter

My aim is to pass filtered data to my controller and then to my template. I've tried not using the filter and everything works as expected. If I even try to use a filter that lets everything through, I don't get any data. I've even tried using false instead of true and fiddling with the argument list of the filter.
I'm using ember-data fixtures to test this. I'm following the name conventions so much of the work is done for me under the hood. That all seems to be working though (otherwise the first example should also have a problem).
Works (arrives in the controller and eventually gets rendered on the page):
App.DomainDirRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('domain_dir');
}
});
Fails (controller gets an empty array):
App.DomainDirRoute = Ember.Route.extend({
model: function(params) {
return this.store.filter('domain_dir', function(item){
return true;
});
}
});
UPDATE (ATTEMPT 1):
Okay, so I've tried a couple of things based on Sam Selikoff's answer. I've defined 4 properties (2 filters, one map, one plain copy) in the controller and tried to display each in the mockup page. Only the property copyDomain gives a result.
Properties in controller:
filteredDomains: Ember.computed.filterBy('domain', 'domain', true),
upperCaseDomains: Ember.computed.map('domain', function(domain, index) {
return domain.toUpperCase() + '!';
}),
filteredDomains2: function() {
return this.get("model").filterBy('domain', true);
}.property('model.#each.domain'),
copyDomains: function(){
result = [];
this.forEach(function(item) {
result.pushObject(item);
})
console.log(result);
return result;
}.property('model.#each.domain')
Mockup:
<ul>
<li>filteredDomains</li>
{{#each domainDir in controller.filteredDomains}}
<li>domainDir.domain</li>
{{/each}}
</ul>
<ul>
<li>filteredDomains2</li>
{{#each domainDir in controller.filteredDomains2}}
<li>domainDir.domain</li>
{{/each}}
</ul>
<ul>
<li>upperCaseDomains</li>
{{#each domainDir in controller.upperCaseDomains}}
<li>domainDir.domain</li>
{{/each}}
</ul>
<ul>
<li>copyDomains</li>
{{#each domainDir in controller.copyDomains}}
<li>domainDir.domain</li>
{{/each}}
</ul>
Filtering is generally done at the controller/component level. store.find makes an AJAX request. Is your goal to only retrieve the filtered subset of data from the server, or to filter the data you already have at the view layer?
Typically if you're just wanting to do some live filtering, you'll do it in the controller. Leave your model hook as this.store.find('domain_dir') and add a filter in your controller:
App.DomainDirController = Ember.Controller.extend({
filteredDomains: function() {
return this.get("model").filterBy('someProp', true);
}.property('model.#each.someProp')
});
You should also check out the computed macros for some shorthands:
App.DomainDirController = Ember.Controller.extend({
filteredDomains: Ember.computed.filterBy('model', 'someProp');
});
Now in your template, you can do
{{#each domain in filteredDomains}}
...

Update list in Aurelia using EventAggregator

I am using app-contacts demo to learn Aurelia, yes I know, it's incomplete as mentioned by #Eisenberg, but then I thought to use EventAggregator to notify the app.js, when I save the contact or create a new contact. Till now everything works fine. I am able to receive the contact object in app.js, but now I would like to update the contact list, which is not working and when I save a contact and update the contacts list in app.js, it gets removed.
Code added in app.js and subscribe method is called in constructor.
subscribe(){
this.ea.subscribe('contact_event', payload => {
console.log(payload);
var instance = JSON.parse(JSON.stringify(payload));
let found = this.contacts.filter(x => x.id == payload.id)[0];
if(found){
let index = this.contacts.indexOf(found);
this.contacts[index] = instance;
}else{
instance.id = this.contacts.length + 1;
this.contacts.push(instance);
}
});
}
No changes made to app.html
<li repeat.for="contact of contacts" class="list-group-item ${contact.id === $parent.selectedId ? 'active' : ''}">
<a href="#" click.delegate="$parent.select(contact)">
<h4 class="list-group-item-heading">${contact.firstName} ${contact.lastName}</h4>
<p class="list-group-item-text">${contact.email}</p>
</a>
</li>
How to update the list?
Update
This worked for me, but not sure what is the right approach
subscribe(){
this.ea.subscribe('contact_event', payload => {
return this.api.getContactList().then(contacts => {
this.contacts = contacts;
});
});
}
Eric L. Anderson does a great job of explaining how this works in his blog post:
Aurelia's Event Aggregator. It's event the same type of code you're trying to do!
Note: it's probably far too late to answer Kishore's question, but I'm putting the link in for others who end up here from a search.

Meteor reactivity not working after Blaze update

I have a detail page which includes a comments part.
Before the 0.8 upgrade the comments where reactive and reflected the change in minimongo, now they only update when the detail object is updated
The code is the following
detail.html
{{#with brick}}
{{> brick_item}}
{{> comment_system bind="url" parentType="brick" context=.}}
{{/with}}
comments.html
<template name="_comment_system">
<section class="comments">
{{#each comments}}
[...]
{{/each}}
</section>
</template>
comments.js
Template._comment_system.created = function(){
var bindFilter = _BindSwitcher[Template._comment_system.bind()()]();
Template._comment_system.subscription = Meteor.subscribe("comments", bindFilter);
};
Template._comment_system.destroyed = function(){
Template._comment_system.subscription.stop();
};
Template._comment_system.helpers({
comments : function(){
var queryOptions = _.extend({sort: {createdAt: -1}}, Template._comment_system.reactive());
if(Template._comment_system.subscription.ready())
return Comments.find({}, queryOptions);
}
});
_BindSwitcher = {
'url' : function(){
return window.location.pathname;
},
'data' : function(){
return 'bind1'
}
}
[...]
The collection and publishing have nothing different from the ordinary.
The problem is that the comments are not reactive. If I insert a comment in mongodb it won't show in the page. If I insert a comment in minimongo it won't show. They appear only after a brick is modified.
And if I take the comment system out of the {{#with brick}} the comments will never update, even after changing the brick.
Before 0.8 there were no problem with the reactivity.
Can someone point out what I'm missing and if I'm using some feature in a way it was not supposed to?
Thanks in advance.
Remove
var queryOptions = _.extend({sort: {createdAt: -1}}, Template._comment_system.reactive());
and put this
var queryOptions = _.extend({sort: {createdAt: -1}});

Meteor template isn't rendering properly

I'm building a notifications page, where the user can see which posts have comments, and I want to display the date of each post, but it's not working.
Here is the code:
<template name="notification">
<li>Someone commented your post, {{postDate}} </li>
</template>
Template.notification.helpers({
notificationPostPath: function() {
return Router.routes.PostPage.path({_id: this.postId});
},
post: function () {
return Post.findOne({_id: this.postId});
},
postDate: function() {
return moment(post.submitted).format('dddd, MMMM Do');
}
});
The console prints this: Exception from Deps recompute: ReferenceError: post is not defined.
Thanks in advance
I assume the error is being flagged on the following line:
return moment(post.submitted).format('dddd, MMMM Do');
Note that you can't refer to helpers from within other helpers like that (and anyway, post is a function) - you need too add another line at the start of the postDate helper like this:
var post = Post.findOne({_id: this.postId});

Categories

Resources