Accessing collection index in Handlebars/Blaze #each loop - html

I'm messing around with a Meteor Leaderboard example. Let's say I wanted to display the index of an item inside a handlebars #each loop:
{{#each players}}
{{> player}}
{{/each}}
<template name="player">
<div class="player {{selected}}">
<span class="index">{{index}}</span>
<span class="name">{{name}}</span>
<span class="score">{{score}}</span>
</div>
</template>
Normally one would write a handlebars helper for this, but I'm having trouble figuring out how to get it working with a Meteor collection.
How would one do this? Thank you.

There is now an #index feature in Blaze:
{{#each players}}
{{> player index=#index}}
{{/each}}
<template name="player">
<div class="player {{selected}}">
<span class="index">{{index}}</span>
<span class="name">{{name}}</span>
<span class="score">{{score}}</span>
</div>
</template>
Template.player.helpers({
index() {
var data = Template.currentData();
if( data ) {
return data.index;
}
}
});

If you are just trying to show the mongo generated id just use _id
<span class="id">{{_id}}</span>
It will show the unique index id in the collection. It won't be pretty.
I may have misunderstood your question. Sorry if I did.

Adding an answer for this question. I had to put some hours figuring it out
In your client
Template.player.data = function(data){
if(type){
return Template[ 'player' ](data);
}
}
In your template
{{#each players}}
{{data this}}
{{/each}}
This will work seamlessly.

Here's how I solved this - not a perfect solution - by using the fact that Mongo typically creates indexes that increase in value.
Template.item.index = function() {
return Items.find().count() - Items.find({_id: {$lte: this._id}}).count() + 1
}
I then use this in the template like so:
{{index}}
Hope this helps!

Related

Meteor #each block issues

I would like to iterate over a Mongo query for the user's collections using the each block.
I have the following html template that should load in different pieces of data from the profile object in the users collection.
To clarify, the users Collection has a services, status and profile object
{{#each profile}}
<div class="profileUser oneDiv">
<div class="profileUserLeft">
<div class="profileUserImage">
<div class="spin"> {{> spinner}} </div>
<img src="{{profile.picturelrg}}" class="profileUserImg">
</div>
<div class="profileUserGraph">
<label for="myChart"><b>Meetup Graph</b>
<br>
<span class="profileMonth"> {{profile.month}} </span>
<br>
<canvas id="myChart"></canvas>
</label>
</div>
</div>
<div class="profileUserRight">
<div class="profileUserName">
<ul>
<li><h1>{{profile.name}}</h1></li>
<li>
<div class="circle" style="background-color: {{online.color}}"></div>
</li>
</ul>
</div>
</div>
</div>
{{/each}}
Here is my helper that sets the query
profile: function() {
return Meteor.users.find({
_id: id
});
}
Currently the page loads in no data.
When I statically query for a property however it works. This is done like so.
profimg: function() {
return Meteor.users.find({
_id: id
}).fetch()[0].profile.picturelrg;
}
How can I be more efficient and use the each block instead of statically searching for each different property utilizing the fetch() method?
each of Blaze takes an array as parameter to loop while find method return a Cursor of MongoDB. What you need to do is fetch the Cursor to return the array
profile: function() {
return Meteor.users.find({
_id: id
}).fetch();
}
However, your logic is not correct. You are finding the profile that matches with the input id, thus the function should be
profile: function() {
return Meteor.users.findOne({
_id: id
});
}
and then you can access the property without the each loop

Angularjs load json into a specific div

I'm new to AngularJS but I love the framework.
What I have right now, is a (stub) single page that loads json data.
JS
var merlinoApp = angular.module('merlino', []);
merlinoApp.controller('mainController', function ($scope, $http) {
...
$http.get('#Url.Action( "consoledatapull", "ConsoleElaborazioni")')
.then(function (res) {
$scope.jobs = res.data.jsonjobs;
$scope.clienti = res.data.jsonclienti;
$scope.console = res.data.jsonconsole;
});
...
});
HTML
<div ng-repeat="roll in jobs | orderBy:sortType:sortReverse | filter:searchJob | filter:searchCliente | filter:searchStato" class="console-row my-row">
...
<div class="console-cell-id console-cell console-cell-padding console-cell-no-border-sx">{{ roll.id }}</div>
...
<div ng-click="collapsed=!collapsed" ng-class="{'console-cell-esito-selected' : collapsed}" class="console-cell-esito console-cell console-cell-no-border-sx">SHORT DESC</div>
<div ng-show="collapsed" class="console-cell-esito-long console-cell console-cell-no-border-sx">{{ roll.esito }}</divng-show></div>
</div>
This populates ng-repeat, and the ng-click shows/hides the `ng-show div.
So far so good(?).
What Ì'm trying to achieve, is to load json data into
<div ng-show="collapsed" class="console-cell-esito-long...
if
<div ng-click="collapsed=!collapsed" ng-class="{'console-cell...
is clicked.
That is each div of ng-repeat, can be loaded with specific data:
<ul>
<li ng-repeat="logelem in jsonlog">
{{ logelem.log }}
</li>
</ul>
I thought about using a function:
<div ng-click="function(id)...
and then load json into a div identified by an id, so i used $index...
The result was, being able to load same data into all divs at once :/
Help would be appreciated.
My suggestion woudl be to add the information to the jobs elements itself.
So for example, the ng-click would become:
<div ng-click="loadData(id, roll)">CLICK ME</div>
and then the loadData would be something like:
$scope.loadData = function(id, roll){
// Do something
roll.result = result;
}
and then you can use the result from that object in the view like you would do in other places. You can then for example hide the object where you want the final result until the variable result is defined.
I think this will be the easiest solution.
Update from comments
Why not change the collapsed value in the method? Or you could use a $watch to listen to changes on the collapsed variable.

angular.js passing function into an object

I think it may be useful if I show the wider scope :) below is my html:
<div class="resSection2 rel">
<div class="proceed rel">
<div ng-repeat="record in records">
<div class="rel fptsans {{record.className()}}">Balkans<i class="icon-check icon-2x posIco"></i></div>
</div>
</div>
</div>
Key factor here is the {{record.className()}} binding which depending on its value determines the behaviour of the record, whether it gets a proper styling or not. as you can see it is a reference to a function. And here is the JS:
var antroApp = angular.module('antroApp', []);
$scope.records = [
{id:0,
className: $scope.probieren,
recordName:$scope.alpeic.length
},
{id:1,
className: $scope.probieren,
recordName:$scope.alpeic.length
}
];
$scope.probieren = function(){
if($scope.records.recordName > 10){
$scope.records.className == 'special'
}
else{
$scope.records.className == 'normal'
}
}
}
antroApp.controller('dialogWindows', dialogWindows);
When I set up the className statically ("special" or "normal") it renders perfectly
but when it comes to a function, it all just gets stuck. really feel helpless about this. any tips appreciated.
You've set it up fine except they have to be defined in the other order, but in your dom when you use it call a function like this:
<div data-ng-repeat="record in records">
<div class="{{ record.className() }}">{{ record.recordName }}</div>
</div>
There's a few more issues with how you're referencing $scope.records.className instead of some index of the array for records but my answer should answer the specific question you have.

How do I populate a bootstrap grid system using handlebars for each command in Meteor.js?

I am trying to display 3 projects per row. My template looks like this: (UPDATED)
<template name="projectList">
{{breakTimeReset}}
<div class=row>
{{#each projects}}
{{> projectItem}}
{{#if breakTime}}
</div>
<div class=row>
{{/if}}
{{/each}}
</div>
</template>
As you can see for each project in the database I output projectItem. I want to output them so every 3 project are wrapped in a
This is my js helper
Template.projectList.helpers({
projects: function() {
return Projects.find();
},
breakTimeReset: function() {
Template.projectList.doCount = 0;
},
breakTime: function () {
count = Template.projectList.doCount + 1;
console.log(count);
Template.projectList.doCount = count;
if (count % 3 == 0) {
console.log("Started break");
return true;
}
else
return false;
}
});
My question is how can I set it up so there are 3 projects per row, and then it knows to insert a new row div after every 3 projects? The way I have it currently setup leads to really funky results, as it is not reliable in that the new div will be inserted before the project.
Check out the results here: http://testprojectapp.meteor.com
You will see that the first row shows up ok but then I get some funky results after that. And if you check out the DOM through viewing page source you will see that the dont match my code which is weird.
Let me know if this is a confusing question. Thanks!
You can group your data before it gets rendered:
Template.projectList.helpers({
projects: function () {
all = Projects.find({}).fetch();
chunks = [];
size = 3
while (all.length > 3) {
chunks.push({ row: all.slice(0, 3)});
all = all.slice(3);
}
chunks.push({row: all});
return chunks;
},
breakTimeReset: function () {
Template.projectList.doCount = 0;
},
breakTime: function () {
count = Template.projectList.doCount + 1;
console.log(count);
Template.projectList.doCount = count;
if (count % 3 == 0)
return "</div><!-- why? --><div class='row'>"
else
return ""
}
});
<template name="projectList">
{{breakTimeReset}}
{{#each projects}}
{{> projectRow }}
{{/each}}
</template>
<template name='projectRow'>
<div class='row span12'>
{{#each row }}
{{> projectItem}}
{{/each}}
</div>
</template>
<template name="projectItem">
<div class="span4">
<h3> {{title}} </h3>
<p> {{subtitle}} </p>
<p> {{description}} </p>
<p><img src="{{image}}"/></p>
<p> {{openPositions}} </p>
</div>
</template>
Sorry I missed so many times, nearpoint!
You can also do that by using plain CSS. The Foundation Framework has a grid system where you need to define the columns in the grid element, not in the child elements itself and someone adapted it to be used together with bootstrap. This means you can simply add more and more elements and the grid will layout them.
https://github.com/JohnnyTheTank/bootstrap-block-grid
<div class="block-grid-xs-2 block-grid-sm-3 block-grid-md-4">
<div>
Content 1
</div>
<div>
Content 2
</div>
<div>
Content 3
</div>
<div>
Content 4
</div>
<div>
Content 5
</div>
<div>
Content 6
</div>
</div>
UPDATE: fails because template engine is helpful, and won't let you have tags spanning templates. It balances each one out, even if you try just injecting text. Nice if you need it, I'm not a fan.
Previous:
Oh, nearpoint stuck to his guns and I was wrong! Handlebars parses each template and 'fixes' it so there are an even number of tags. Edited to reflect this.
The template
<template name='sureties'>
{{breakTimeReset}}
{{#each allSureties }}
{{name}}
{{{breakTime}}}
{{/each}}
</template>
Some helper functions
Template.sureties.breakTimeReset = ->
Template.sureties.docCount = 0
''
Template.sureties.breakTime = ->
count = Template.sureties.docCount + 1 or 0
console.log count
Template.sureties.docCount = count
if count % 3 is 0
return "</div><div class="">
else
return ""

How do you get json #attributes item in a meteor template

I have a json that is converted from XML and kept "#attributes" :
{"stop":"1021","route":"0057","direction":"1","departures":{"departure":[
{"#attributes":{"accurate":"1","headsign":"Rennes R"},"content":"2013-03-25T12:00:23+01:00"},
{"#attributes":{"accurate":"0","headsign":"Rennes R"},"content":"2013-03-25T12:20:00+01:00"},
{"#attributes":{"accurate":"0","headsign":"Rennes R"},"content":"2013-03-25T12:40:00+01:00"}]}},...
you can here access to the properties in javascript [1] with :
departure[0]["#attributes"].accurate
but if you want to grab it in a template with Meteor, how do you do this?
[1] JSON #attributes
I would suggest accessing the field in a function such as
Templates.your_template.attributes = function()
{
return this["#attributes"];
}
in your template
{{attributes}}
the template in the html side will look like this :
<template name="status">
<div class="line {{status}}_line">
{{stop}}
{{#each departures.departure}}
{{> attributes}}
{{/each}}
</div>
</template>
<template name="attributes">
<div class="attributes">
{{content}}
accurate : {{{access_attributes this}}}
</div>
</template>
and on the js side :
Template.attributes.access_attributes = function(context) {
return context["#attributes"].accurate
}