I have a huge table with too many columns to fit on-screen. I want the user to be able to select which columns to show using checkboxes. The checkboxes part is easy but I'm not sure how to show the table using handlebars. Is there some helper I could make that would help? I'm using Meteor.js.
{stats:
{symbol: 'A', stat1: 5, stat2, 24.3, stat3: 293, stat4: 3},
{symbol: 'B', stat1: 4, stat2, 24.3, stat3: 293, stat4: 3},
{symbol: 'C', stat1: 2, stat2, 24.3, stat3: 293, stat4: 3}
}
{columns:
{key: 'stat1', name: 'Stat 1'},
{key: 'stat2', name: 'Stat 2'},
{key: 'stat3', name: 'Stat 3'},
{key: 'stat4', name: 'Stat 4'}
}
{currentUser: {columnsToShow: ['stat1', 'stat3']}}
<table>
{{#each stats}}
<tr>
<td>{{symbol}}</td>
{{#each columns}}
{{#if inArray key currentUser.columnsToShow}}
<td>
{{!-- the following is what i'm not sure how to do --}}
{{stats[key]}}
</td>
{{/if}
{{/each}}
</tr>
{{/each}}
</table>
inArray is a helper I made that returns true if it finds key in the array or false if it doesn't.
Here's what I expect the table to look like
A 5 293
B 4 293
C 2 293
EDIT: got it to work
{{#if inArray key currentUser.columnsToShow}}
<td>
{{returnArrayValueByKeyName key ../../this}}
</td>
{{/if}}
Handlebars.registerHelper('returnArrayValueByKeyName', function(keyName, array) {
return array[keyName];
})
You can change your columns helper to a stats_to_show helper that returns the stats for just the columns that you want:
<table>
{{#each stats}}
<tr>
<td>{{symbol}}</td>
{{#each stats_to_show}}
<td>
{{this}}
</td>
{{/each}}
</tr>
{{/each}}
</table>
The stats_to_show helper would look like this
Template.stats_table.stats_to_show = function() {
result = [];
for (column in currentUser.columnsToShow) {
// We're using the fact that a single element of stats is bound to
// `this` when this helper is called.
result.push(this[column];
}
return result;
}
Sorry if my Javascript syntax is off. I've been exclusively using Coffeescript lately.
Related
I am trying to iterate using the properties of an object to dynamically print a table having an array with the properties and an object with the values of each property.
I don't know how to do the 2 iterations using hbs express from handlebars
people: [{
name: "ken",
lastname: "grace",
age: 10
},
{
name: "ron",
lastname: "bond",
age: 20
}];
properties = ["name","lastname", "age"];
HTML CODE:
<table>
<thead>
<tr>
{{#each properties as |property index|}}
<th>
<span>{{property}}</span>
</th>
{{/each}}
</tr>
</thead>
<tbody>
{{#each people}}
<tr>
{{#each properties}}
<th>
{{!-- trying something like: --}}
{{!-- {{people.property}} --}}
</th>
{{/each}}
</tr>
{{/each}}
</tbody>
</table>
As user #76484 mentioned, you want to use the built-in lookup helper:
The lookup helper allows for dynamic parameter resolution using Handlebars variables. It can be used to look up properties of object based on data from the input.
In your specific example, you'd probably want to store your people and properties iterations in a block parameter (e.g., named |person| and |property|), as well as using ../ on your inner loop since the context has changed.
Putting that all together for you example, the HBS markup might look like:
<table>
<thead>
<tr>
{{#each properties as |property index|}}
<th><span>{{property}}</span></th>
{{/each}}
</tr>
</thead>
<tbody>
{{#each people as |person|}}
<tr>
{{#each ../properties as |property|}}
<th>{{lookup person property}}</th>
{{/each}}
</tr>
{{/each}}
</tbody>
</table>
See this playground link for the resulting HTML as well.
I've got a template helper that returns the value of a Session, in this case it's returning in the number 1:
Template.Student.helpers({
curWeek: function () {
return Session.get('CurrentWeek').substr(0, 1);
},
My template has a table and I'm trying to print to the table a portion of it depending on the value of the helper function. So I have some logic in the template to print the right portion. But it's not obeying the logic. Even though the value of curWeek returns the value 1, the template runs the logic under {{#if curWeek 2}} as well, so both are in the table. I only want the part under {{#if curWeek 1}} to run, since that's what the value is. Am I not using the logic correctly?
<template name="Student">
{{#modalizeBody}}
<table class="bordered narrow">
<thead>
<tr>
<th>Name</th>
<th>Shift</th>
<th>Age</th>
<th>Sex</th>
<th>Level</th>
<th>Sun</th>
<th>Mon</th>
<th>Tue</th>
<th>Wed</th>
<th>Thu</th>
<th>Fri</th>
<th>Sat</th>
</tr>
</thead>
<tbody>
{{#each StudsWk1Master}}
{{#if curWeek 1}}
<tr>
<td>{{FullName}}</td>
<td>{{RoomWk1}}</td>
<td>{{calculateAge Bdate}}</td>
<td>{{Sex}}</td>
<td>{{Level}}</td>
<td>{{formatName this.Teachers.Week1.Sunday}}</td>
<td>{{formatName this.Teachers.Week1.Monday}}</td>
<td>{{formatName this.Teachers.Week1.Tuesday}}</td>
<td>{{formatName this.Teachers.Week1.Wednesday}}</td>
<td>{{formatName this.Teachers.Week1.Thursday}}</td>
<td>{{formatName this.Teachers.Week1.Friday}}</td>
<td>{{formatName this.Teachers.Week1.Saturday}}</td>
</tr>
{{/if}}
{{/each}}
{{#each StudsWk1Master}}
{{#if curWeek 2}}
<tr>
<td>{{FullName}}</td>
<td>{{RoomWk2}}</td>
<td>{{calculateAge Bdate}}</td>
<td>{{Sex}}</td>
<td>{{Level}}</td>
<td>{{formatName this.Teachers.Week2.Sunday}}</td>
<td>{{formatName this.Teachers.Week2.Monday}}</td>
<td>{{formatName this.Teachers.Week2.Tuesday}}</td>
<td>{{formatName this.Teachers.Week2.Wednesday}}</td>
<td>{{formatName this.Teachers.Week2.Thursday}}</td>
<td>{{formatName this.Teachers.Week2.Friday}}</td>
<td>{{formatName this.Teachers.Week2.Saturday}}</td>
</tr>
{{/if}}
{{/each}}
</tbody>
</table>
{{/modalizeBody}}
</template>
Your helper isn't testing for equality. You have:
{{#if curWeek 1}}
But your helper just returns the current week and doesn't expect a parameter.
Just add the parameter to your helper function and then return a boolean:
Template.Student.helpers({
curWeek: function (value) {
return Session.get('CurrentWeek').substr(0, 1) === value;
},
I have a helper function which is returning array of objects and each object of array has key publishers which is an object containing keys. Each key again has a object.
priceData:function(){
var colection=[
{contract:"nn",publishers:{GVM:{ask:1,bid:2},SET:{ask:6,bid:3}}},
{contract:"BB",publishers:{GVM:{ask:11,bid:99},SET:{ask:23,bid:34}}}
]
return colection
}
Now in template I am trying to use it like this
<table class="table">
<tbody>
{{#each priceData}}
<tr>
{{#with publishers}}
<td>{{ask}}</td>
<td>{{bid}}</td>
{{/with}}
</tr>
{{/each}}
</tbody>
</table>
Can I use #with in a #each iteration because it gives error like this. If not then how can I show such collection information in a table?Right now its empty table
There is no problem with each and with, you can combine them and nest at your will. The only thing to keep in mind is context: each of the blocks goes deeper into the context but at the same moment allows access outer contexts (which I personally wouldn't recommend). So if you remove all the typos and use the whole code in this way:
<table class="table">
<tbody>
{{#each priceData}}
<tr>
{{#with publishers}}
<td>{{ask}}</td>
<td>{{bid}}</td>
{{/with}}
</tr>
{{/each}}
</tbody>
</table>
then everything will be fine. But make sure the data structure corresponds with this code. But it doesn't.
What you need is to access ask and bid within publishers through either GVM or SET. Let's pretend you need the former:
<table class="table">
<tbody>
{{#each priceData}}
<tr>
{{#with publishers}}
<td>{{GVM.ask}}</td>
<td>{{GVM.bid}}</td>
{{/with}}
</tr>
{{/each}}
</tbody>
</table>
Let's deconstruct the whole code to make the picture clearer.
When you use
{{priceData}}
then you link to what the helper returns, i.e.
[{
contract: "nn",
publishers: {
GVM: {
ask: 1,
bid: 2
},
SET: {
ask: 6,
bid: 3
}
}
}, {
contract: "BB",
publishers: {
GVM: {
ask: 11,
bid: 99
},
SET: {
ask: 23,
bid: 34
}
}
}]
So when you use
{{#each priceData}}
...
{{/each}}
you dive into the context of what the helper returns and iterate over items of the array. For example, the first one would be
{
contract: "nn",
publishers: {
GVM: {
ask: 1,
bid: 2
},
SET: {
ask: 6,
bid: 3
}
}
}
Next what you do is
{{#with publishers}}
...
{{/with}}
For the first item of array the context is
GVM: {
ask: 1,
bid: 2
},
SET: {
ask: 6,
bid: 3
}
and for the second is
GVM: {
ask: 11,
bid: 99
},
SET: {
ask: 23,
bid: 34
}
Then you're trying
{{ask}}
and this is where your code fails because there's no ask property of the structure within current context. But there are properties GVM and SET. So pick one you like and use it like this:
{{GVM.ask}}
Hope it helps.
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();
});
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}}