Meteor reactivity not working after Blaze update - javascript

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

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 and Handlebars Iterate Over a Set Array

I'm working on learning Ember and am trying to do some small ideas with it. Currently, I am trying to receive text field input to filter a list and return the matching results. I have all of this working, you know, the 'hard' stuff. However, the part that isn't working is Handlebars reading the 'title' property of my array that I am returning. It's just blank.
Here is my template:
<script data-template-name="application" type="text/x-handlebars">
{{input type="text" value=searchString placeholder="Search..."}}
{{filterMovies}}
<ul>
{{#each searchResults}}
<li>{{title}}</li>
{{/each}}
</ul>
</script>
And now my controller:
App.ApplicationController = Ember.Controller.extend({
filterMovies: function() {
var self = this,
searchString = self.get('searchString'),
searchResults = [],
filterArrLength = null,
theFullMovieList,
theFilteredMovieList = [];
if (!searchString) {
return;
}
var url = 'http://www.json-generator.com/api/json/get/clVKyWQSnC';
Ember.$.getJSON(url).then(function(data) {
theFullMovieList = data;
theFullMovieList.filter(function(movie) {
if (movie.title.toLowerCase().startsWith(searchString)) {
theFilteredMovieList.push(movie);
}
});
console.log(theFilteredMovieList);
self.set('searchResults', theFilteredMovieList);
});
}.property('searchString')
});
I have tried printing using {{this}}, {{this.title}}, {{searchResults.title}}, and {{title}} with no luck. However, logging the array shows the correct values.
Any ideas? View On CodePen
Your each syntax is invalid. You have to use new syntax:
<ul>
{{#each searchResults as |movie|}}
<li>{{movie.title}}</li>
{{/each}}
</ul>
See working demo on CodePen.

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}}
...

Grouping by date using Meteor

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

Computed.alias not updating bind-attr

I recently started using Ember.js. In my small application I currently have problems regarding Ember.computed.alias, because an {{#if}}-section is updated properly, but the bind-attr helper in the same template is not updated accordingly.
The application controller and the action influencing the value look as follows:
App.ApplicationController = Ember.ObjectController.extend({
isEditing: false,
actions: {
toggleEdit: function() {
var a = this.get('isEditing');
this.set('isEditing', !a);
}
}
});
The controller taking care of the template causing problems:
App.CategoriesController = Ember.ArrayController.extend({
needs: ['application'],
isEditing: Ember.computed.alias('controllers.application.isEditing'),
general: function() { // example depending on the alias
var result = this.filterBy('type', 1);
if (!this.get('isEditing')) {
result = result.filterBy('isHidden', false);
}
return result;
}.property('#each.type', '#each.isHidden', 'isEditing'),
// ......
The related template:
<ul id="categories">
{{#if isEditing}}YES!{{else}}NO!{{/if}}
{{#each general}}
<li {{bind-attr class=":general isEditing:editing"}}>
{{name}}
</li>
{{/each}}
</ul>
When the action toggleEdit is triggered, the {{#if}} section is updated and swaps between YES! and NO!, but the editing class is not applied to the list element. I tried encapsulated the alias into another property of the controller depending on the alias, but without success.
I assume it's a beginners mistake, but I can't figure out what I am overlooking.
Thanking you in anticipation.
isEditing is no longer in scope, use controller.isEditing, sorry phone response
Here's an example that would keep it in scope, but I'm fully qualifying it just to show you.
{{#each item in general}}
<li {{bind-attr class=":general controller.isEditing:editing"}}>
{{item.name}}
</li>
{{/each}}

Categories

Resources