Pagination with meteor - meteor

am trying to list 9 items each time and i found alethes:pages that can help accomplish it.
i didn't understand how exactly it should be implemented.
My collection is created with
Products = new Mongo.Collection("products");
so i created the Pages inside /lib folder
Pages = new Meteor.Pagination(Products, {
perPage: 9,
sort: {
createdAt: -1
}
});
Am confused on how to use the Pages to list the items? below is my template to list the items. Am calling the template inside another template to list the items.
This is the template
<template name="list_products">
{{#each applications}}
<div class="col-sm-4 col-lg-4 col-md-4">
<div class="thumbnail">
<img src="{{previewImage}}" alt="">
</div>
</div>
{{/each}}
</template>
How do i apply Pages to list_products template?
sorry for my english

This how you have to define your template and item template for pages.
Pages = new Meteor.Pagination(Products, {
perPage: 9,
sort: {
createdAt: -1
}
templateName: "list_products",
itemTemplate: "list_products_item",
});
Then your list_products have the following templates {{> pages}} and {{> pagesNav}} like this :
<template name="list_products">
{{> pages}}
{{> pagesNav}}
</template>
And here how you have to create your each item template which will show your item and you don't have to use any #each for that. Basically it will render each time based of your item per page value:
<template name="list_products_item">
<div class="col-sm-4 col-lg-4 col-md-4">
<div class="thumbnail">
<img src="{{previewImage}}" alt="">
</div>
</div>
</template>

Related

I lose data context when i generate template with parameters

when I generate subtemplate in #each helper and i add parameter, then i lose data context, what is normally visible.
I found workaround by passing data fields to template by
{{> productItem parameter="test" name=name details=details}}
, but for more complicated collections that would be very tiresome... isn't there better option to solve that problem ?
<template name="main">
{{#each products}}
{{> productItem parameter="test"}}
{{/each}}
</template>
<template name="productItem">
<div class="product">
<p>{{name}}</p>
<p>{{details}}</p>
<p>{{parameter}}</p>
</div>
</template>
And javascript :
Template.main.helpers({
products: function(){
return Products.find({});
}
});
you are creating a new context ( it doesn't magically merge everything ), but its easy enough to include the original context.
you go :-
{{> productItem product=this parameter="test"}}
then
<template name="productItem">
<div class="product">
<p>{{product.name}}</p>
<p>{{product.details}}</p>
<p>{{parameter}}</p>
</div>
</template>
or
<template name="productItem">
<div class="product">
{{#with product}}
<p>{{name}}</p>
<p>{{details}}</p>
{{/with}}
<p>{{parameter}}</p>
</div>
</template>

How to call Object items in array with Mongo/Meteor?

In my Mongo database, I have products and each of these products have images.
I would like to know how I can call each image in put them in a Meteor template. I know things like {{#each}}{{/each}} exist, but I don't know how to capture the images object.
With this code...
Template.products.helpers({
product: function () {
return ProductList.find();
}
});
I am able to call the first image like:
<img src="{{images.[0]}}" alt="{{title}}"/>
I could hardcode the rest of the images, but I would like to do this dynamically. Any tips?
EDIT: Here is the expected HTML output (the extra classes on .content__product are added dynamically via a separate function):
<section class="content__products">
<figure class="content__product selected">
<img src="/images/product/tt-shirt-01.jpg" alt="Time Travel Tee">
</figure>
<figure class="content__product move-down">
<img src="/images/product/tt-shirt-02.jpg" alt="Time Travel Tee">
</figure>
<figure class="content__product">
<img src="/images/product/tt-shirt-03.jpg" alt="Time Travel Tee">
</figure>
</section>
each works for both cursors and arrays, so you can do something like this:
{{#each products}}
<h2>{{title}}</h2>
{{#each images}}
<img src={{this}} alt={{../title}}>
{{/each}}
{{/each}}
Recommended reading: A Guide to Meteor Templates & Data Contexts
{{#each}} only accepted array or cursor of Mongo collection. So you have to change your object to array and make another template.
This is sample code for you.
if(Meteor.isClient){
Template.product.helpers({
list : function(){
return Products.find({});
}
});
Template.productImg.helpers({
imgList: function(){
var imgs = [];
_.each(this.images, function(img){
imgs.push({imgPath: img});
});
return imgs;
}
});
}
<template name="product">
{{#each list}}
{{> productImg}}
{{/each}}
</template>
<template name="productImg">
{{#each imgList}}
<img src="{{imgPath}}" alt="{{../title}}"/>
{{/each}}
</template>
For an individual product page I would do it like this:
Template.products.helpers({
'products': function() {
return ProductList.find();
}
});
Multiple images per product:
<section class="content__products">
{{#each products}}
<figure class="content__product">
{{#each images}}
<img src="{{this}}" alt="{{../title}}">
{{/each}}
</figure>
{{/each}}
</section>
Single image per product:
<section class="content__products">
{{#each products}}
<figure class="content__product">
<img src="{{images.[0]}}" alt="{{../title}}">
</figure>
{{/each}}
</section>
Okay, so the code posted here helped me out, but didn't solve my issue out of the box. Here is how I changed my code:
if (Meteor.isClient) {
Template.products.helpers({
product: function () {
return ProductList.find();
}
});
Template.product.helpers({
imgList: function () {
var imgs = [];
_.each(this.images, function (img) {
imgs.push({imgPath: img});
});
return imgs;
}
});
}
And, my template:
<template name="product">
<section class="content__products">
{{#each imgList}}
<figure class="content__product">
<img src="/{{imgPath}}" alt="{{../title}}"/>
</figure>
{{/each}}
</section>
</template>

Template.dynamic is not passing data context

I have a list template (#each) in a package that I plan to use across many different collections. Since the template is in a package they are not easily customizable. So I figured this was a great example to use Template.dynamic. Everything works except passing data.
.. I pull the data into the routed page and manipulate the data to match the dynamic template.
Template.usersIndex.helpers({
items: function() {
var users = Meteor.users.find({}).fetch();
var items = users.filter(function(user) {
return user;
}).map(function(user){
return {
name: user.profile.name,
description: user.emails[0].address,
tidbit: "hello"
};
});
return items
}
});
... the data passes perfectly to the usersIndex template.
<template name="usersIndex">
<div id="gc-users-index-navbar">
<h2>Title</h2>
</div>
<div id="gc-users-index" class="inner-content">
{{> Template.dynamic template="strataIndexItem" data="items" }}
</div>
</template>
... But no dice, the dynamic template is rendered but no data.
<template name="themeIndex">
<div class="list-group">
{{#each items }}
<div class="list-group-item">
<div class="row-content">
<div class="least-content">{{tidbit}}</div>
<h4 class="list-group-item-heading">{{name}}</h4>
<p class="list-group-item-text">{{description}}</p>
</div>
</div>
<div class="list-group-separator"></div>
{{/each}}
</div>
</template>
You pass data as string?
{{> Template.dynamic template="strataIndexItem" data="items" }}
You should pass data as variable, without ""
{{> Template.dynamic template="strataIndexItem" data=items }}
Also check if your strataIndexItem template is named strataIndexItem:
<template name="strataIndexItem">
...
</template>

How to write Iron-router nested template?

I have 2 templates:
1) mainLayout.html -> general layout which must be used by all pages. (e.g. page title, navbar, footer)
Router.configure({
layoutTemplate: 'mainLayout'
})
<template name="mainLayout">
{{> header}}
<div class="container-fluid">
{{> yield}}
</div>
</template>
2) specialLayout.html -> custom layout which is inheriting main-layout.html but with additional template (e.g. side/tab menu)
How should I define specialLayout? Note that specialLayout should have the title, navbar, and footer defined in mainLayout.
If I have route X which want to use specialLayout, how should I write it?
I don't know any simple method at this moment, but most things can be achieved by several less elegant ways:
Copy your common parts into separate templates and use them in both layouts, i.e.:
<template name="mainLayout">
{{> navbar}}
<div>
{{> content}}
</div>
{{> footer}}
</template>
<template name="specialLayout">
{{> navbar}}
<div>
{{> content}}
{{> sidebar}}
</div>
{{> footer}}
</template>
Make your special part an option in the main layout instead of a separate one:
<template name="mainLayout">
...
<div>
{{#if layout.renderSidebar}}
<div class="col-2">>
{{> yield 'sidebar'}}
</div>
{{/if}}
<div class="{{#if layout.renderSidebar}} col-10 {{else}} col-12 {{/if}}">
{{> yield}}
</div>
</div>
...
</template>
Then in the appropriate routes enable sidebar in the data:
this.map('pathName', {
...
data: function() {
return {
layout: {renderSidebar: true},
...
};
},
});

Dynamic templates and routing in Meteor.js

I am developing a meteor.js application. I have two main templates/pages, home.html and groups.html. I render these templates according to the selection of main menu. In home template, I just show basic informations about the website. But in groups template, I have side menu which has timeline, chat, group blog options, and according to the selection of side menu, I render timeline or chat or groupblog templates inside groups template. I succeeded this with two different methods.
Can you please tell me if any of them is correct approach, and if they both are, which one is better to use?
In the first approach, is there any way to wait to render sub-template until data is ready, like waitOn property in iron-router?
First approach: I am using dynamic template, and rendering and setting data contex of sub-templates by using Session variable.
layout.html
<template name="layout">
<div>
{{> header}}
<div id="main" class="container">
{{> yield}}
</div>
</div>
</template>
groups.html
<template name="groups">
<div class="row">
<div class="row-fluid">
<div class="col-md-9 col-lg-9">
{{> dynamictemplate}}
</div>
</div>
</div>
</template>
dynamictemplate.html
<template name="dynamictemplate">
{{#DynamicTemplate template=getTemplate data=getData}}
Default content when there is no template.
{{/DynamicTemplate}}
</template>
dynamictemplate.js
Template.dynamictemplate.helpers({
getData: function () {
var tempname="timeline";
if(Session.get("menuitemselected")!=null){
tempname =Session.get("menuitemselected");
}
if(tempname=="timeline"){
return {test:123};
}else if(tempname=="calendar"){
return {groupId:this._id};
}
},
getTemplate: function () {
var tempname="timeline";
if(Session.get("menuitemselected")!=null){
tempname =Session.get("menuitemselected");
}
return tempname;
}
});
Second approach, I am defining new routes for all sub-templates in routes, and I am using yield with region property in home template.(I do not know if i am supposed to use yield in any place other than layout.html)
layout.html
<template name="layout">
<div>
{{> header}}
<div id="main" class="container">
{{> yield}}
</div>
</div>
</template>
groups.html
<template name="groups">
<div>
<div class="col-md-3">
{{> sidemenu}}
</div>
<div id="main" class="col-md-9">
{{> yield region="detailrender"}}
</div>
</div>
</template>
router.js
.....
this.route('groupdetail', {
path: '/groupsmain/:_id',
layoutTemplate: 'layout',
yieldTemplates: {
'timeline': {to: 'detailrender'}
},
data: function() { return Groups.findOne(this.params._id);
}
});
this.route('groupdetailcalendar', {
path: '/groupsmain/:_id/calendar',
layoutTemplate: 'layout',
template: 'groupdetail',
yieldTemplates: {
'calendar': {to: 'detailrender'}
},
data: function() { return Groups.findOne(this.params._id);
.....
});

Resources