Meteor {{#each in}} not scoping down correctly - meteor

I'm trying to use the feature {{#each test in calculation}} in a template, but am getting an error saying "No such function: test". Here is a link to my code and I was hoping someone could show me where my mistake would be.
https://gist.github.com/claytonzaugg/c4191111159be68106f4
Thank you!
Clayton

You can either change your template helper to:
Template.ListCalculations.helpers({
test: function() {
return Calculations.find();
}
});
Or your html {{#each}} to:
{{#each calculations}}
<tr>
<td>{{test.testNumber}}</td>
<td>{{test.testName}}</td>
<td>{{test.inputOne}}</td>
<td>{{test.inputTwo}}</td>
<td>{{test.inputThree}}</td>
<td>{{#linkTo route="editCalculation"}}<span class="glyphicon glyphicon-edit" aria-hidden="true"></span>{{/linkTo}}</td>
</tr>
{{/each}}
As #Michael Floyd mentioned, the in calculations is spurious.

Try editing the helpers to the following
Template.ListCalculations.helpers({
'test': function() {
return Calculations.find();
}
});
and the template binding to this in the each loop
{{#each test}}
<tr>
<td>{{testNumber}}</td>
<td>{{testName}}</td>
<td>{{inputOne}}</td>
<td>{{inputTwo}}</td>
<td>{{inputThree}}</td>
<td>{{#linkTo route="editCalculation"}}<span class="glyphicon glyphicon-edit" aria-hidden="true"></span>{{/linkTo}}</td>
</tr>
{{/each}}

Related

How to do foreach in Meteor with Mongo?

Have collection
Peoples = new Mongo.Collection('peoples');
Peoples.insert({
name: ["Mark", "John", "Kate"]
});
I want to show all names in name
<template name="pTable">
<tr class="trJob">
<td>
{{#each names}}
{{> peopleName}}
{{/each}}
</td>
</tr>
</template>
<template name="peopleName">
<div>{{name}}</div>
</template>
What in my Temlate helpers
Template.pTable.helpers({
names: function(){
return Posts.tags;
}
});
Template.peopleName.helpers({
name: function(){
return Posts.tags.find();
}
});
I know that i have sh*** code in my Template helpers, any idea how to make it good ?
It must look like (in DOM)
<td>
<div>Mark</div>
<div>John</div>
<div>Kate</div>
</td>
simple array example
Template.home.helpers({
names: function(){
return [1,2,3];
}
});
<template name="home">
{{#each names}}
{{this}}
{{/each}}
</template>
will print:
1 2 3
each item becomes "this" inside the each loop. if you call another template within the loop, then its "this" will be populated by the item
Since you have different names for your collection, I will stick with the first one Peoples
Here is how I would proceed with your helpers:
Template.pTable.helpers({
names: function(){
return People.find({_id:yourId},{fields:{name:1}}).fetch();
}
});
And your peopleName template would be like this:
<template name="peopleName">
<div>{{this}}</div>
</template>
If you need to get all the names of all your documents, I need to nest your {{#each names}} into another {{#each doc}} where doc helper is like this (updated names as well) :
Template.pTable.helpers({
doc: function(){
return People.find().fetch();
},
names: function(){
return People.find({_id:this.id},{fields:{name:1}}).fetch();
});

Collections not showing on page

I have published a countries collection which I want to show in a table in the countriesList template. So I have added this to the router:
Router.route('/countries_list', {
name: 'countriesList',
waitOn: function() {
return Meteor.subscribe('countries');
},
data: function() {
return Countries.find();
}
});
And this is how the template looks like:
{{#each countries}}
<tr>
<td>{{name}}</td>
</tr>
{{/each}}
But the page stays empty. However, the collection is filled on the client, if I check the browser console and do Countries.findOne();, I get this result:
Object {_id: "WWJhMBne4CiEdbbdg", name: "England"}
So what am I doing wrong here?
You template is making the assumption that the cursor is being stored in coutries. It isn't. It would be if your data hook looked like:
return {countries: Countries.find()};
As your code is written, the cursor is the context for your template so this should work:
{{#each this}}
<tr>
<td>{{name}}</td>
</tr>
{{/each}}

Meteor RangeError: Maximum call stack size exceeded. on keypress event

Im trying to make a search box to filter down results of my returned collection in the client.
however when i actually try searching I'm getting the above error in the console.
RangeError: Maximum call stack size exceeded.
here is a look at my code.
<body>
{{#isolate}}
<header class="row-fluid">
{{> modules}}
</header>
{{/isolate}}
<div id="main" class="span11">
{{#if currentUser}}
{{#isolate}}
{{> customers_list}}
{{/isolate}}
{{#isolate}}
{{> contacts_list}}
{{/isolate}}
{{/if}}
</div>
</body>
my search form in inside the modules template
<template name="modules">
{{templateLogger "modules"}}
<ul id="module_list" class="nav">
{{#each list}}
<li>
{{name}}
</li>
{{/each}}
<form><input type="text" id="search"></form>
</ul>
and my customers_list template that I'm trying to filter the results
<template name="customers_list">
<table class="table">
<tr>
<th>Name</th>
<th>Address</th>
<th>City</th>
<th>State</th>
<th>Zip</th>
<th>Phone</th>
</tr>
{{#each record}}
<tr>
<td>{{name}}</td>
<td>{{address}}</td>
<td>{{city}}</td>
<td>{{state}}</td>
<td>{{zip}}</td>
<td>{{phone}}</td>
</tr>
{{/each}}
</table>
</template>
and here is the event handler for the search form
Template.modules.events({
'keypress input#search': function (event) {
Session.set("currentFilter", $('input#search'));
}
});
and the form helper do display the results
Template.customers_list.record = function() {
qry = Session.get("currentFilter") || "";
if (qry != "") {
return Customers.find({$or: [ {'name': qry}, {'address': qry}, {'city': qry}, {'state': qry} ] });
} else {
return Customers.find({competitor: null}, {sort: {name: 1}});
};
}
I have no clue what the is causing this error from what i was able to read on other SO posts about the error it seems like its a infinite loop however those were not meteor specific questions and i don't know if that would make a difference? also if there is an infinite loop i cant find it.
any help would be grateful.
This error occurs when you pass large object as an argument to your method. For me for example the first Time I encountered this error, was when I passed a Meteor.Collection as an argument :s . I worked around that by passing the collection name as a String and then using eval() in the Methods to get the Collection on which proceed.
Conclusion: Always use strings, integers, small arrays or really small objects as arguments for methods called from your event handlers.
Changing this:
Template.modules.events({
'keypress input#search': function (event) {
Session.set("currentFilter", $('input#search'));
}
});
To This:
Template.modules.events({
'keyup input#search': function (event) {
Session.set("currentFilter", $('input#search').val());
}
});
I believe you just need the .val() on the jquery dom reference of the input field. Additionally I would recommend using keyup for the event for something like this.
For getting the results out like you want you likely want to use a regular expression. Here's what I'm using in my app.
Template.hudlies.found = function() {
var searchVal = Session.get("searchFilter");
if (searchVal != "") {
var searchResults = Hudlies.find({ name: { $regex: '^.*' + searchVal + '.*', $options: 'i' } });
};
return searchResults;
};

Dynamically insert template into table row

I have a table with data coming from a collection. When user clicks on a row I want to replace the content of the row with a form to edit the content. What would be the meteor way to do it without jQuery, if possible?
<template name="table">
<table>
{{#each items}}
{{> showrow}}
{{else}}
</table>
</template>
<template name="showrow">
<tr>
<td>{{name}}</td>
</tr>
</template>
<template name="editrow">
<tr>
<form>
… form html …
</form>
</tr>
</template>
Essentially, it's about replacing the showrowtemplate witn the editrow for onw row, I think. Is that a reasonable approach? Any pointers?
You could use a logical helper
<template name="table">
<table>
{{#each items}}
{{#if editmode}}
{{>editrow}}
{{else}}
{{> showrow}}
{{/if}}
{{/each}}
</table>
</template>
Then in your template helper
Template.table.editrow = function() {
return (this.editmode)
}
this lets you access the data context that would be in the collection for that particular item in the loop. So if you had a editmode:true for that item it would use the edit row instead.
Ok, that was easier than expected. 1:0 for Meteor:
I used the MongoDB _id as identifier of each row, in a data attribute: data-id="{{_id}}".
Then I set up a click event handler on <tr>-elements:
Template.booking.events({
'click tr': function(event, template) {
Session.set(editBookingId, event.currentTarget.getAttribute('data-id'));
}
});
A template helper listens to incoming ids and returns true if the ids match:
Template.booking.helpers({
'isEdited': function(id) {
return Session.get(editBookingId) == id;
}
});
In the template, I decide with {{#if}} whether to display the normal row or an edit dialog:
{{#if isEdited _id}}EDIT{{/if}}
Very little code. Very nice. Thanks for the pointers.

How to access outer {{#each}} collection value in the nested loop

What is the standard way to access outer #each collection values in the loop?
for example:
<template name="example">
{{#each outerCollection}}
<tr>
{{#each innerCollection}}
<td>{{aaa}}</td>
{{/each}}
</tr>
{{/each}}
</template>
Template.example.aaa = function(){
// cannot access outerCollection values
}
in above Template.example.aaa, this points to the inner collection.
I cannot find way to access outerCollection items.
My solution is like below, I am defining my own helper function.
Is it a standard Meteor way to achieve this purpose?
<template name="example">
{{#each outerCollection}}
<tr>
{{#each innerCollection}}
<td>{{myHelper ../outerItem innerItem}}</td>
{{/each}}
</tr>
{{/each}}
</template>
Handlebars.registerHelper('myHelper', function (outItem, inItem) {
// can access outerCollection via outerItem
});
I found a similar question for the case of inner event handler access.
I think you've answered this yourself! Using ../ is documented in https://github.com/meteor/meteor/wiki/Handlebars.
You can use below code to fetch outer collections.
suppose you have collection called as Collection.Customer and Collection.RechargePlan and you are using both in a template for updating Customer.
Customer = {"name":"James", "rechargeplan":"monthly"};
RechargePlan = [{"rechargeplan": "monthly"},{"rechargeplan": "yearly"}];
//Inside template, Bydefault Customer is available.
{{#each RechargePlan}}
{{#if equals ../rechargeplan rechargeplan}}
//Hurray Plan matches
{{/if}}
{{/each}}
In above code, ../rechargeplan is actually Customer.rechargeplan, ../ actually went one step above heirarchy and then accessed the field if available, since Customer is already available to template, it's field is picked up.

Resources