I am looking at Meteor pagination today.
I am interested in this repo:
https://github.com/alethes/meteor-pages
The initial code shown looks simple:
this.Pages = new Meteor.Pagination("collection-name");
and:
<body>
{{> collection-name}}
</body>
<template name="collection-name">
{{> pages}}
{{> pagesNav}} <!--Bottom navigation-->
</template>
I want to paginate this demo:
https://github.com/meteor/simple-todos
The code I see there simplifies to this:
Tasks = new Mongo.Collection("tasks");
if (Meteor.isServer) {
// This code only runs on the server
Meteor.publish("tasks", function () {
return Tasks.find({})})}
if (Meteor.isClient) {
// This code only runs on the client
Meteor.subscribe("tasks");
// ...
}
and:
<body>
<ul>
{{#each tasks}}
{{> task}}
{{/each}}
</ul>
</body>
<template name="task">
<li>
{{text}}
</li>
</template>
Perhaps my brain is a bit slow today.
It is not obvious to me how to paginate the above code.
How do I use
github.com/alethes/meteor-pages
to paginate the above code from simple-todos?
Been a while since I've used meteor-pages, but you should be able to just do replace Tasks = new Mongo.Collection("tasks"); with this.Tasks = new Meteor.Pagination("tasks"); - common code between client and server.
Basically meteor pages just creates a wrapper around a mongo collection and applies search and filter criteria.
If you're familiar with coffeescript make sure to check out their /examples directory in the repo.
Also, the settings https://github.com/alethes/meteor-pages#settings will help explain some of the defaults like items per page etc.
Related
Hey everyone, thank you very much for your help. Question is edited per suggestions in the comments.
I'm new to Mongo and Meteor.
I have a collection "posts" with a field "slug".
The "post" template is populating correctly with each post's values. Slug value is always something like "my-great-post".
I need to get the text value for the _id's slug, which will be different each time the template is accessed, encode it, write a string, and spit the string back out into the template.
Things tried
can't return a value for "this.slug" or "this.data.slug" in either template helpers or onRendered, even though collection is defined and correctly populating spacebars values in the template
"this" returns "[object Object]" to console.log
app crashes when I try to javascript encode and deliver a string from the helper, probably I don't fully understand helper syntax from the documentation
(I followed advice in the comments to avoid trying to create scripts in the template html, so below is more information requested by everyone helping on this thread)
- Template html -
{{#with post}}
<div class="blog-article">
<div class="blog-header">
<div class="left">
<!-- title -->
<h1 class="post-title">{{title}}</h1>
<div class="holder">
<div class="post-tags">
<!-- tags -->
{{#each tags}}
<span>{{this}}</span>
{{/each}}
</div>
</div>
</div>
</div>
<div class="blog-post">
<div class="blog-copy">
<!-- date -->
<div class="post-date">{{post_date}}</div>
<!-- social -->
<div class="blog-social">
<!--
<a class="so-facebook" target="_blank" href="need to encode slug here"></a>
-->
</div>
<!-- ============== post ============== -->
{{{content}}}
<!-- ============ end post ============ -->
</div>
</div>
</div>
{{/with}}
- Template js -
Template.post.onCreated(function() {
var self = this;
self.autorun(function() {
var postSlug = FlowRouter.getParam('postSlug');
self.subscribe('singlePost', postSlug);
});
});
Template.post.helpers({
post: function() {
var postSlug = FlowRouter.getParam('postSlug');
var post = Posts.findOne({slug: postSlug}) || {};
return post;
}
// can't get these working in a helper, out of helper they crash the app
// console.log(this.slug);
// console.log(this.data.slug);
});
Template.post.onRendered( function () {
// these do not work
// console.log(this.slug);
// console.log(this.data.slug);
});
db.posts.findOne();
{
"_id" : ObjectId("576c95708056bea3bc25a91f"),
"title" : "How Meteor Raised the Bar For New Rapid-Development Technologies",
"post_date" : "May 28, 2016",
"image" : "meteor-raised-the-bar.png",
"slug" : "how-meteor-raised-the-bar",
"bitlink" : "ufw-29Z9h7s",
"tags" : [
"Tools",
"Technologies"
],
"excerpt" : "sizzling excerpt",
"content" : "bunch of post content html"
}
If some one can solve this using any method, I will accept answer with joy and gratitude most intense.
The problem is probably with the parent template, rather than this one. The way that Meteor works is that the JS files are separated from the HTML, so don't try to include a <script> tag in the HTML.
The first thing is that you have to load all of your documents into the client. (NOTE: once you've got the hang of that, then you can worry about only loading the documents that you need).
To do that, you need a collection and a publication. By default all collections are automatically published completely, so unless you removed the autopublished module, then I'll assume that it is still loaded.
So let's start with the parent template. In this case, I'm going to just loop through all of the posts in the collection and display them using the innerTemplate.
<template name=parent>
<ul>
{{#each post}}
{{> innerTemplate}}
{{/each}}
</ul>
</template>
And now our inner template might look like this:
<template name=innerTemplate>
<li>{{slug}}</li>
</template>
The end result will be a simple list with each slug.
Now, to link everything together, we need to create a JS file, which will:
1. define the collection on both client and server
2. pass the collection to the parent template
This file should be accessible to both the client and the server.
posts = new Mongo.Collection('posts');
if(Meteor.isClient) {
Template.parent.helpers({
posts() {
return Posts.find();
}
});
}
Now, if you want to do something with 'slug' in the JS file, you could do something like this:
if(Meteor.isClient) {
Template.innerTemplate.helpers({
upperCaseSlug() {
return this.slug.toUpperCase();
}
});
}
Then, you could refer to upperCaseSlug in your template, like thus:
<template name=innerTemplate>
<li>{{upperCaseSlug}}</li>
</template>
A few things about Meteor:
You should never see a pattern such as:
<script type="text/javascript">
...some code
</script>
Because Meteor combines all your js files into one big file and includes it automatically in your app. You should never have to declare your own script in this way.
Secondly, you should never have to get the value of a data object by reading the DOM. The data context of each template gives you your data in the variable this.
In either a helper or template event you can refer to this and be assured that you're going to get exactly the data being displayed in that instance of the template.
Having now seen your template code it's now apparent that your template has no data context - you set the data context inside your {{#with post}} and its associated helper but that doesn't end up creating the this you need one level below.
So... #Nathan was on the right track except that he assumed you were iterating over a cursor instead of just looking at a single post.
Take all html you have between your {{#with post}} and {{/with}} and put it in a new template, say postDetail then make your outer template:
<template name="post">
{{#with post}}
{{> postDetail}}
{{/with}}
</template>
Now your postDetail template will get a data context equal to the post object automatically and your helpers can refer to this safely.
Template.postDetail.helper({
slugURI{
return "/"+encodeURI(this.slug);
}
});
Then in your postDetail template you can get the encoded slug with:
<a class="so-facebook" target="_blank" href={{slugURI}}>
I like to work with meteor, but I have a problem I can't find a solution for.
In the template file I have this code:
<template name="klussenboard">
<h2>Klussen</h2>
<div class="klussenboard">
{{#each klus}}
{{#if status=1}}
<li>
<a class="startlink" href="#"><img src="/images/starten.png"></a>
</li>
{{/if}}
{{/each}}
</div>
</template>
This is the js client code
Template.klussenboard.klus = function () {
return Klussen.find({"status": { $gt: 0 }}, {
sort: {datum: -1}
});
};
But this doesn't work. How can I do a statement in a template file?
Looking forward to an answer.
Spacebars (meteor's templating library), much like Handlebars (that it is based on) doesn't execute arbitrary expressions like, say, angular.js's templates.
If you change the statement you're trying to write into a helper method, like so (feel free to pick a better name!):
<template name="klussenboard">
<h2>Klussen</h2>
<div class="klussenboard">
{{#each klus}}
{{#if isEnabled}}
<li>
<a class="startlink" href="#"><img src="/images/starten.png"></a>
</li>
{{/if}}
{{/each}}
</div>
</template>
You could then define the isEnabled helper in any client side .js file - say, client/klussenboard.js like so:
Template.item.isEnabled = function() {
return this.status == 1;
}
So, this, in helper functions is
This assumes that you are in a context where status is a variable (which, based on your question, you are)
This would then reactively update whenever the status variable changes.
I want to create complex blog page with meteor. I have a template with two sub template as below:
<template name="singlePostPage">
{{> post }}
{{#each comments}}
{{> comment}}
{{/each}}
</template>
I want to load post when page is loading and after post load completely then load comments. (like disqus comment system that load after entire page load)
Please guide me how to do this and what packages may useful for this scenario?
You can set a session variable or reactive variable when the post template has been rendered, and then have a handlebars {{#if}} to show the comments based on the value of that variable. Something like below should work.
.js file (Sessions)
Template.post.onRendered(function() {
Session.set("postRendered", true);
});
Template.singlePostPage.helpers({
postRendered: function() {
return Session.get("postRendered");
}
});
Just make sure that the postRendered Session variable is set to false or null when you first load the singlePostPage template. If you want to use a reactive variable:
Add this package:
meteor add reactive-var
And use this .js code:
var postRendered = new ReactiveVar(false);
Template.post.onRendered(function() {
postRendered.set(true);
});
Template.singlePostPage.helpers({
postRendered: function() {
return postRendered.get();
}
});
For both examples you can use this .html file
<template name="singlePostPage">
{{> post }}
{{#if postRendered}}
{{#each comments}}
{{> comment}}
{{/each}}
{{/if}}
</template>
I'm new to Meteor and Javascript.
I'm trying to implement the sort library found here:
https://github.com/RubaXa/Sortable/tree/master/meteor
I know this is probably simple, but the simpliest invocation of the code here:
{{sortable }}
still leaves me a bit baffled. I've tried passing collections like:
{{sortable PlayersList}} but, have no idea what the output is supposed to be. I learn by example, can someone help me out by giving me the quickest implementation of the library?
This is my first time posting on a forum in a long time. I usually can Google-Fu my way around.
Here is my html file:
`
sortof
Welcome to Meteor!
{{> hello}}
Unsorted:
{{#each showplayers}}
<li>{{name}}: {{score}}</li>
{{/each}}
Sorted:
{{#sortable items=PlayersList}}
{{#each name}}
hi
<li>{{name}}: {{score}}</li>
{{/each}}
{{/sortable}}
`
and here is my web output:
`
Welcome to Meteor!
Unsorted:
Bob: 0
Larry: 0
Henry: 0
Sorted:
`
Thanks!
The following should work:
<template name="myTemplate">
{{#sortable items=players}}
</template>
Template.myTemplate.helpers({
players: function () {
return Players.find();
}
});
And for more complex examples, see:
HTML: https://github.com/RubaXa/Sortable/blob/master/meteor/example/client/define-object-type.html
JS: https://github.com/RubaXa/Sortable/blob/master/meteor/example/client/define-object-type.js
I'm trying to figure out how to implement the load more functionality like Telescope. This is what I have originally:
// Iron Router
Router.route('/posts', {
name: 'posts.index',
waitOn: function () {
return Meteor.subscribe('posts', Session.get('postsLimit');
},
data: function () {
return { posts: Posts.find({}, { sort: { createdAt: -1 } }) };
},
action: function () {
this.render();
}
});
// client/views/posts_list.html
<ul>
{{#each posts}}
<li>{{ title }}</li>
{{/each}}
</ul>
<a href"#" class="load-more">Load more</a>
// client/views/posts_list.js
var POSTS_INCREMENT = 3;
Session.setDefault('postsLimit', POSTS_INCREMENT);
Template.PostsIndex.events({
'click .load-more': function (e, tmpl) {
Session.set('postsLimit', Session.get('postsLimit') + POSTS_INCREMENT);
return false;
}
}
});
It makes sense that Meteor will rerender the list when the postsLimit changes. I'm just curious how Telescope did it without re-rendering the list and only render the new posts. From what I see from the code, instead of storing the limit in the Session, the author uses the route top/:limit? and instead of using waitOn, they use onBeforeAction. It's hard to pinpoint which part of the code helps prevent re-rendering the list. Could someone please help explain in detail how they did it?
The part that triggers the re-rendering is actually waitOn. By using waitOn, you're telling Iron Router to redirect you to the loading template while you wait, which is what triggers the re-rendering and sticks you back up at the top of the page.
This is waitOn's job, and it works great when going from page to page, but is obviously not ideal when re-rendering the same page.
By the way, note that the new subscriptions option can also trigger the same behavior (if you've set a global loading template).
So this is why we're using onBeforeAction in this specific case. This pattern is explained in more details in Discover Meteor, by the way.
Don't know if this is helpful but to load more posts all you have to do is add {{> UI.dynamic template=postsLoadMore}} in the postList template.
<template name="posts_list">
{{> UI.dynamic template=postsListIncoming data=incoming}}
<div class="posts-wrapper grid grid-module">
<div class="posts list">
{{#each posts}}
{{> UI.dynamic template=post_item}}
{{/each}}
</div>
</div>
{{> UI.dynamic template=postsLoadMore}}
</template>