Given a years worth of months and data that returned may only apply to specific months, how can I render this in blaze please, but also render 0's where an applicable record does not exist?
What I'm working with:
{{#each month in months}}
{{#each recordDataset }}
{#if equals recordDataset.period month}<td>{{ recordDataset.value}}</td>{/if}
{{/each}}
{{/each}}
This nested loop obviously returns too many because it is looping through 2 separate sets of data. I can think how to do this in other languages of course but not in blaze.
For example, what would be ideal would be:
{{#each month in months}}
{{#if recordSet['month'] == month}}
<td>{{ recordDataset.value}}</td>
{{else}}
<td> </td>
{{/if}}
{{/each}}
But I don't see how I can achieve this.
Any help would be hugely appreciated.
Based on your code example, recordDataSet has a property month which you'd like to compare to each month in months. Given that, you can just create an equals operator and use that for comparison:
Template.registerHelper( 'equals', ( v1, v2 ) => {
return v1 === v2;
});
{{#each month in months}}
{{#if equals recordDataSet.month month}}
<td>{{recordDataset.month}}</td>
{{else}}
<td>0</td>
{{/if}}
{{/each}}
Since I don't have the schema of your recordDataSet, you'll have to adjust according to your needs.
Related
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.
This question already has answers here:
How can I get the index of an array in a Meteor template each loop?
(6 answers)
Closed 7 years ago.
I am using meteor Shark branch.
Is there a way to access array index inside each block helper in spacebars?
I am looking for something like this.
{{#each humans}}
{{this.arrayIndex}}
{{/each}}
meteor >= 1.2
Spacebars gained a lot of functionality in 1.2, including a native #index. Helpers are no longer needed to solve this problem - you can simply do this:
<template name="showHumans">
<ul>
{{#each humans}}
<li>{{#index}}: {{name}}</li>
{{/each}}
</ul>
</template>
meteor < 1.2
I saw a similar example using template helpers in the meteor book in the "animations" chapter. You can apply a map to the humans cursor in order to add an index like so:
Template.showHumans.helpers({
humans: function() {
return Humans.find({}, {sort: {hotness: -1}}).map(function(human, index) {
human.rank = index;
return human;
});
}
});
<template name="showHumans">
<ul>
{{#each humans}}
<li>{{rank}}: {{name}}</li>
{{/each}}
</ul>
</template>
As taken from the spacebars documentation:
You can use a special variable #index in the body of #each to get the
0-based index of the currently rendered value in the sequence.
In Meteor 1.0.2.1, you can do the following:
{{#each humans}}
{{this}}
{{/each}}
This is because #each iterates through the array, making the this in each loop simply equal to the current value.
I have a {{#each}} that's essentially iterating through the users collections. I now wish to check if the user is an admin to set a switch (materialize). A simplified version:
{{#each getUsers}}
testing: {{_id}} {{#if isAdmin "tTEScMyjCedano2oT"}}checked="checked"{{/if}}
{{/each}}
Here I am hard coding in the _id parameter in the {{#if}} and it works as expected. The isAdmin function works correctly, the {{#if}} works and the {{_id}} works as well (prints out the correct id).
But of course I do not want to hard code the id passed to isAdmin but want it to be {{_id}} however it doesn't work. i.e.
{{#each getUsers}}
testing: {{_id}} {{#if isAdmin "{{_id}}"}}checked="checked"{{/if}}
{{/each}}
does not work and neither does
{{#each getUsers}}
testing: {{_id}} {{#if isAdmin "{{../_id}}"}}checked="checked"{{/if}}
{{/each}}
nor
{{#each getUsers}}
testing: {{_id}} {{#if isAdmin {{id}}}}checked="checked"{{/if}}
{{/each}}
What is the correct way to do this?
Don't use double quotes nor curly braces :
{{#each getUsers}}
testing: {{_id}} {{#if isAdmin _id}}checked="checked"{{/if}}
{{/each}}
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.
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.