How to pass data between Meteor Template Helpers? - javascript

Meteor Newbie here!
I have a page where all the open orders are displayed. The order details are stored in a collection. A Template helper will return the order details.
Template.delivery.helpers({
openOrders: function(){
return Orders.find({status: "open"});
}
});
The template look some what like this.
{{#if openOrders}}
{{#each openOrders}}
Date: {{createdAt}}
Total items: {{items.length}}
Location: {{location}} //It prints the location _id
{{/each}}
{{/if}}
The Order Collection only have the _id of the location. The Location details are stored in a Collection named Locations.
I want to display the location name (which is stored in the Location collection) instead of the _id.
I created a Template helper which returns the Location details, but how can I link these to helpers so that the Location name is displayed instead of Location _id?

As you're using mongodb in a relational database fashion, you need to install publish-composite package to make sure all the necessary data are subscribed.

When you use each, it will set the this to the current thing that is being iterated over. This will allow you to use this in your helper to perform lookups. So in this case, if you're using a helper to get the orders:
orders: function () {
return Orders.find({ status: "orders" });
}
Then when you iterate over it with {{#each}}, this is set to the current order, meaning your location helper with look like this:
location: function () {
return Locations.findOne(this.locationId);
}
Putting it all together in the template it would be like:
{{#if Template.subscriptionsReady}}
{{#each orders}}
<h1 class="title">Order #{{_id}}</h1>
{{#with location}}
<div class="location">
<span>Latitude: {{ latitude }}</span>
</div>
{{/with}}
{{/each}}
{{/if}}
Keep in mind: this will only work if you also publish your locations.

Related

How to refer parent template in quickform attribute _id

Consider Below Code.
{{#each assignments}}
{{#with eachClientDetails}}
{{#quickRemoveButton collection=assignment _id=this._id }}
Delete
{{/quickRemoveButton}}
{{/with}}
{{/each}}
In above code, I am iterating each assignment and each assignment has single Client Detail. With each Client Detail I am adding Delete button.
Helper:
eachClientDetails(){
var client = Clients.find({_id: this.clientId}).fetch()[0];
console.log(client);
return client;
}
But the problem is, while assigning attributes to _id of quickForm, I can only assign data from current context(i.e. this._id). All I need is to access context of assignment (desired like _id=../_id). But I get below error,
Can only use `this` at the beginning of a path.
Instead of `foo.this` or `../this`, just write `foo` or `..`.
Is it possible using any helper and stuff to get the parent templates _id
Your issue with overwriting contexts could be solved by using #each in and #let instead of #each and #with:
{{#each assignment in assignments}}
{{#let client=(eachClientDetails assignment)}}
{{#quickRemoveButton collection=assignment _id=assignment._id }}
Delete {{client.name}}
{{/quickRemoveButton}}
{{/let}}
{{/each}}
Here, {{client.name}} has been added just to show how to access client's fields.
And helper's code:
eachClientDetails(assignment){
var client = Clients.findOne({_id: assignment.clientId});
console.log(client);
return client;
}

Creating a many-to-many relationship between 2 mongodb collections by ids

I have two collections. One is called Posts and the other is called Categories. In the posts collection, are individual posts that each contain an array of id's called categories which are id's of the categories the individual post belongs to stored in the posts.
The second collection is the Categories collection which contains the categories each of the posts belong to
Goal
In my template, I am displaying each post as its title, content, image and author as well as the Category names which come about by linking the Category Ids in the Posts collection to the individual categories in the Category collection
<template name="latest">
{{#each posts}}
<div>{{> category}}</div>
<h5 class="latest-title">{{title.rendered}}</h5>
<img class="latest-img" src="{{featured_image_thumbnail_url}}" alt="" />
{{/each}}
</template>
In my category template
<template name="category">
{{#each categories}}
{{name}}
{{/each}}
</template>
In my category.js
Template.category.helpers({
categories(){
return CategoryCollection.find({ id: parseInt(this.categories) });
}
});
As you can see, I want to display the names of the categories belonging to a post, they are in an array because a post might have 3 categories it belongs too. but I can't seem to get it to work.
Edit
This is my edit to include the $in
Template.category.helpers({
categories(){
return CategoryCollection.find({ id: {$in: this.categories }});
}
});
And this is my template
<template name="category">
{{#each categories}}
{{name}}
{{/each}}
</template>
It doesn't seem to be working.
Progress
It wasn't working because I hadn't assigned categories to my example post, the above edited code is the answer
Another solution I'm using for this kind of stuff is just showing the categories in the array of that post, without even a helper. Here is what I do...
Inside the method:
//the categories is what you pass from the client as an array of strings
//IE: ['cat1', 'cat2']
categories.forEach(function(cc){
const cat = Categories.findOne({name: cc});
if(!cat){
Categories.insert({
name: cc,
count: 1
});
} else {
//increment count if it exists
Categories.update({name: cc}, {
$inc:{
count: 1
}
});
}
});
The reason I insert with count 1 and increment the count if category exists is for multiple different use cases such as:
Showing existing categories on search so that it always returns existing documents
In case of edit/delete post, if count == 1, delete the category if count > 1, decrement count of that category.
Showing a reference of existing categories when a user is adding/editing posts. Depending on what they write on the input I return Category recommendations with a regex.
In the post, just show the category names from the post. No need to find category.
<!--
see that its {{this}} not {{name}} because
we saved the categories to the post as an array of strings
we'd do {{name}} if we were looping through the categories collection
-->
{{#each categories}}
{{this}}
{{/each}}
If you need to access the category from the DB in the post like click events, you can do a quick Categories.findOne({name: this.name})
I see that you save other stuff to the Category collection which I'd probably save to the post itself and some, I wouldn't even save and generate the necessary stuff client side if they're like links etc.
You want to use the $in operator:
return CategoryCollection.find({ id: {$in: this.categories }});

How to get a single record to the template from model in emberjs

I'm new to ember js. I was trying to get a single record from my mongo db database but the query to server returns the full list view instead of a record.
templates/profile.hbs
{{#each item in model}}
{{item.userName}}
{{/each}}
routes/profile.hbs
export default Ember.Route.extend({
model: function() {
return this.store.find('user',{userName:'sanka'});
}
});
New syntax for printing arrays is:
{{#each model as |item|}}
{{item.userName}}
{{/each}}
Does your backend have a support for this kind of filter? Go check your network tab. Otherwise we won't be able to tell what your issue is. But it really looks as if you dont have support in your mongoDB. Because you're actually retrievering records, so it looks like the filter is "broken" or "non-existing"
To query for a single record that is not in an array you should be using
findRecord(type,id)
peekRecord(type, id)
queryRecord(type, {query})
http://emberjs.com/blog/2015/06/18/ember-data-1-13-released.html

Using current each data inside a query in pathFor iron-router

Just started playing around with meteor and I'm trying to use iron-router for the routing. Here is my data structure:
team
_id
name
tags:[{name,counter}]
And here is the linking I'm trying to use in the template
{{#each team.tags}}
{{this.name}} <span class="count-list">{{this.counter}}</span>
{{/each}}
And my router has:
route('/team/:_id') // And I get the search through the GET property... this.params.query
But it doesn't like query='search='+this.name, how can I make this work?
Because it's a GET method, this should work:
{{#each team.tags}}
{{this.name}} <span class="count-list">{{this.counter}}</span>
{{/each}}
Otherwise you would have to build the URL within a helper upfront (or registerHelper function), as spacebars doesn't allow for compound operations.

Ember.js not re-rendering template after Model loaded

I'm learning Ember.js using a Ruby on Rails API server. I've got the routes, template, and model all setup and working - but the template is never re-rendered once the data has been loaded from the API server. I'm not getting any error messages, and I know the customer is being loaded from looking at the Ember inspector.
Customer list is supposed to be displayed after start
Customer list is being loaded correctly from the API server:
Router
// javacripts/router.js
App.Router.map(function() {
this.resource('customers', { path: "/" });
});
Customers Route
// javascripts/routes/customer_routes.js
App.CustomersRoute = Ember.Route.extend({
model: function() {
return this.store.find('customer');
},
renderTemplate: function() {
this.render('customers/index');
}
});
Customer Model
// javascripts/models/customer.js
App.Customer = DS.Model.extend({
name: DS.attr('string')
});
Customer Index Template
// javacripts/templates/customers/index.js.handlebars
<ul>
<li>start</li>
{{#each customers}}
<li>{{name}}</li>
{{/each}}
</ul>
Store
// javacripts/store.js
App.ApplicationAdapter = DS.ActiveModelAdapter.extend({
namespace: 'api/v1'
});
Instead of
{{#each customers}}
It should read either
{{#each controller}}
{{name}}
{{/each}}
or
{{#each customer in controller}}
{{customer.name}}
{{/each}}
I have recently posted two screencasts. One showing how to get started with a new application, and one showing how to setup Grunt:
https://www.youtube.com/watch?v=T-s34EVSE_0
https://www.youtube.com/watch?v=kPaHt_F3VcU
You might also get some use out of a talk I gave earlier this year as well, which goes through developing a simple application during the talk, including Ember Data.
https://www.youtube.com/watch?v=KH5RreHtaaQ
Your customers/index template is referencing a "customers" collection that doesn't exist.
Your route's model hook is returning an array of records, which makes Ember generate an Ember.ArrayController with its model set to your array of customers. It doesn't have a property called "customers", so the {{#each customers}} doesn't have anything to iterate over. If you change it to just {{#each}} (because this in this scope references the controller, which is array-like) or {{#each model}} (to explicitly access the model array of the ArrayController), it should work correctly.
Also, your renderTemplate hook in the Route is the default behavior, so you can just delete it.
Incidentally, I'd recommend just using an Ember JSBin or something while you're starting out and learning the basics, so when you need to ask for help, you can just link to the bin, and people have live code they can work with to help you out, with a minimum of effort. That low barrier to entry makes a big difference to people who are doing free work for internet points.

Categories