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/';
Related
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.
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.
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);
}
})
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}});
I'm following John Papa's jumpstart course about SPA's and trying to display a list of customers loaded via ASP.NET Web API the knockout foreach binding is not working. The Web API is working fine, I've tested it on it's own and it is returning the correct JSON, because of that I won't post the code for it. The get method simply returns one array of objects, each with properties Name and Email. Although not a good practice, knockout is exposed globaly as ko by loading it before durandal.
I've coded the customers.js view model as follows
define(['services/dataservice'], function(ds) {
var initialized = false;
var customers = ko.observableArray();
var refresh = function() {
return dataservice.getCustomers(customers);
};
var activate = function() {
if (initialized) return;
initialized = true;
return refresh();
};
var customersVM = {
customers: customers,
activate: activate,
refresh: refresh
};
return customersVM;
});
The dataservice module I've coded as follows (I've not wrote bellow the function queryFailed because I know it's not being used)
define(['../model'], function (model) {
var getCustomers = function (customersObservable) {
customersObservable([]);
var options = {url: '/api/customers', type: 'GET', dataType: 'json'};
return $.ajax(options).then(querySucceeded).fail(queryFailed);
function querySucceeded(data) {
var customers = [];
data.forEach(function (item) {
var c = new model.Customer(item);
customers.push(c);
});
customersObservable(customers);
}
};
return {
getCustomers: getCustomers
};
});
Finaly the model module was built as follows:
define(function () {
var Customer = function (dto) {
return mapToObservable(dto);
};
var model = {
Customer: Customer
};
return model;
function mapToObservable(dto) {
var mapped = {};
for (prop in dto)
{
if (dto.hasOwnProperty(prop))
{
mapped[prop] = ko.observable(dto[prop]);
}
}
return mapped;
}
});
The view is then simply a list, it is simply:
<ul data-bind="foreach: customers">
<li data-bind="text: Name"></li>
</ul>
But this doesn't work. Any other binding works, and I've looked on the console window, and it seems the observable array is being filled correctly. The only problem is that this piece of code doesn't show anything on screen. I've reviewed many times the files but I can't seem to find the problem. What's wrong with this?
You can use the knockout.js context debugger chrome extension to help you debug your issue
https://chrome.google.com/webstore/detail/knockoutjs-context-debugg/oddcpmchholgcjgjdnfjmildmlielhof
Well, I just spent a lot of time on an local issue to realize that the ko HTML comment format, if used, should be like this:
<!-- ko foreach: arrecadacoes -->
and NOT like this:
<!-- ko: foreach: arrecadacoes -->
: is NOT used after ko...
I know this question is a little old but I thought I'd add my response in case someone else runs into the same issue I did.
I was using Knockout JS version 2.1.0 and it seems the only way I can get the data to display in a foreach loop was to use:
$data.property
so in the case of your example it would be
$data.Name
Hope this helps
I don't see anywhere in your code that you've called ko.applyBindings on your ViewModel.
KO has a known issue while using foreach in a non-container element like the one above <ul> so you have to use containerless control flow syntax.
e.g.
<ul>
<!-- ko foreach: customers-->
<li data-bind="text: Name"></li>
<!-- /ko -->
</ul>
Ref: http://knockoutjs.com/documentation/foreach-binding.html