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.
Related
each running after onRendered and Tracker.autorun(if foo is binding subscription data context).
so i cant catch thateach` work is when done.
how to know each is work done, or rework and done?
is it unknown?
Below is an example.
<template name="something">
{{#each foo}}
<bar>bar</bar>
{{/each}}
</template>
I don't see a real use case for this but you can use a helper here that does not add anything to the render output:
<template name="something">
{{#each foo}}
<bar>bar</bar>
{{isDone #index foo}}
{{/each}}
</template>
Template.something.helpers({
isDone(index, arr) {
if (index === arr.length - 1) {
// this was the last element
// to be rendered. do whatever
// you want here
}
}
})
Not that this is not really a best practice and you should think about why you need to know this? If you have performance issues with your rendering you want review your whole template code design and refactor where necessary.
http://jsfiddle.net/0ttb7pug/1/
I do not have the desired result, only first loop executed
{{#each loop1}}
<ul>{{val1}}
{{#each loop2}}
<li>{{val2}}</li>
{{/each}}
</ul>
{{/each}}
Since your second {{#each}} is within the first, its context has changed to that of each object in the first array. To resolve your issue, you need to get access to the root context of your template data (or at least the context above), which can be achieved with either ../loop2 (which takes you up one context) or #root.loop2 (which takes you to the top-most context)
{{#each loop1}}
<ul>{{val1}}
{{#each ../loop2}} //or #root.loop2
<li>{{val2}}</li>
{{/each}}
</ul>
{{/each}}
I have collections like this:
I want to iterate over object.questions.teema for example.
I have helper:
Template.game.helpers({
theGame: function() {
var theGame = Game.findOne({_id:"LhQmaZKW8eJNenyX9"})
console.log(theGame)
return theGame
}
});
and template:
<template name="game">
{{#with theGame}}
{{#each theGame.questions}}
{{teema}}
{{/each}}
{{/with}}
</template>
But it doesnt work, what is wrong with the template?
'#each theGame.questions' Will not work inside the #with, because you can access the 'theGame' object directly.
The point is when you try to get theGame object inside the #with it will return you undefined, because 'theGame' object does not have theGame property, Which you want to access inside #with block.
<template name="game">
{{#with theGame}}
{{#each questions}}
//Thie #each because you have nested array. As I can see in your console log.
{{#each this}}
{{teema}}
{{/each}}
{{/each}}
{{/with}}
</template>
What is {{teema}} supposed to be?
Regardless, as you can see from your console.log statement, {{theGame.questions}} returns another array. But that array returns objects. This is really hard to query for with Blaze.
The better solution would be to flatten it out so that your data is shaped like this:
questions: [
{
a: 'asdfkjah',
level: 'askdjfhal',
q: 'asdkfh',
teema: 'asdkfjh'
vaartus: 100
},
{
...
}
]
This way you don't have an array nested in an array. That will allow you to:
{{#with theGame}}
{{#each theGame.questions}}
{{this.teema}}
{{/each}}
{{/with}}
theGame.questions is an array (that you iterate over) of array of objects which have the teema key. So you still need to iterate over the 2nd level array, or define a specific item in that array before you can eventually reach the object with teema property.
Maybe something like:
{{#with theGame}}
{{#each questions}}
{{#each this}}
{{this.teema}}
{{/each}}
{{/each}}
{{/with}}
But it depends on why you have these 2-level arrays in the first place.
<script id="contact-row" type="text/x-handlebars-template" >
{{#each rows}}
<tr>
{{getInputField #index "country" country }}
{{#each contactData}}
{{getInputFieldForData #index "contractName" contractName }}
{{/each}}
</tr>
{{/each}}
I want to get the index of the parent in the inner #each loop. I tried ../#index but that gives error.
Looks like things have changed...
To get the index of a parent {{#each}} block from within a child {{#each}} block use the {{#../index}} syntax.
{{#each foo}}
{{#index}} // Parent Index Reference
{{someProperty}} // Parent property
{{#each baz}}
{{#index}} // Child Index Reference
{{#../index}} // Parent Index Reference <--
{{someProperty}} // Child property
{{/each}}
{{/each}}
The link in the accepted answer has this solution, just posting the details here for posterity's sake.
It looks like this is not currently possible the way you want to do it: https://github.com/wycats/handlebars.js/issues/491
But you could set the index to a new variable in the outer scope to access it.
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.