Handlebars get first element that passes a condition - handlebars.js

Using handlebars, I want to get the first item in an array that matches a conditional statement.
Here is an example object:
var objects = {[
"A": {
"isRed": false,
"name": "Yellow Circle"
},
"B": {
"isRed": true,
"name": "Red Square"
},
"C": {
"isRed": true,
"name": "Red Triangle"
}]};
I want to do something sort of like this
{{#each objects}}
{{#if this.isRed}}
{{#if #first}} {{!-- Want the first item that matches the above conditional --}}
{{this.name}}
{{/if}
{{/if}}
{{/each}}
Expected output:
Red Square
I believe that {{if #first}} won't work because it is looking at the second element in the array so it fails the condition.

Related

Is there any way to nest 2 different object in handlebars with node js

I am trying to use each using handlebars for iterating over 2 objects of type array, when I iterate over them individually that works fine; but when there is a nesting of both inner object each isn't working.
a = [{a: "A"}, {a: "B"}, {a: "C"}]
b = [{b: "X"}, {b: "Y"}, {b: "Z"}]
Now these both objects can be iterated fine with
{{#each a}}
{{this.a}}
{{/each}}
{{#each b}}
{{this.b}}
{{/each}}
But it wont work for
{{#each a}}
{{this.a}} //this is getting printed
{{#each b}}
{{this.b}} //this isn't getting printed
{{/each}}
{{/each}}
(I've not mentioned any HTML syntax to reduce any confusions )
Your problem is that your data context is different when you are within the #each block. Within #each, your context is the current element in the iteration, { a: "A" }, { b: "B" }, etc. To access an object of the parent context you use Handlebars Paths:
{{#each a}}
{{this.a}}
{{#each ../b}}
{{this.b}}
{{/each}}
{{/each}}

How to iterate custom inner array object with handlebars?

I am trying to iterate a custom inner array object "choices". See below example, "choices" can have different number of objects inside.
{
_id: 1,
"question": "a",
"choices": [
{"a" : 1},
{"b" : "blablabla"},
{"c" : 128},
{"d" : "blebleble"}
],
"answer": "b",
"points": "10"
},
{
_id: 10,
"question": "j",
"choices": [
{"a" : 10},
{"b" : "blablabla"}
],
"answer": "b",
"points": "10"
}
I am able to display "question", "answer", "points".
This is the template I am using in main.html
<template name="question">
<button>Click Me</button>
{{#with object}}
{{question}}
{{#each choices}}
??
{{/each}}
{{answer}}
{{points}}
{{/with}}
</template>
Any help is appreciated. If you guys need more info please let me know.
You need to mend your data structure a bit as below
choices:[
{key:"a",value:1},
{key:"b",value:"bla"},
{key:"c",value:"blabla"},
{key:"d",value:"blablabla"}
]
Now in your template
{{#each choices}}
<span>Your choice is {{key}}.{{value}}</span>
{{/each}}
It should help
Thank you

Use a function inside {{#each element}} in Meteor?

In a Meteor project, I have a collection of documents which can have one of two formats. To simplify, a given document may either have a type property or a label property. I would like to display this is a multiple select element, using whichever property they have to identify them.
Here's a working example:
HTML
<body>
{{> test}}
</body>
<template name="test">
<select name="elements" size="2">
{{#each elements}}
<option value="{{id}}">{{id}}: {{type}}{{label}}</option>
{{/each}}
</select>
</template>
JavaScript
Template.test.helpers({
elements: function () {
return [
{ id: 1, type: "type" }
, { id: 2, label: "label" }
]
}
})
This happily displays:
1: type
2: label
However, this is a simplification. The actual data that I want to display is more complex than this. I would rather not put all the concatenation logic into the HTML template. I would much rather call a JavaScript function, passing it the current document, and get the string to display. Something like:
<option value="{{id}}">{{functionToCall_on_this}}</option>
How could I do this with Meteor?
Answering my own question, I have found that I can change my template to include this line...
<option value="{{id}}">{{id}}: {{string}}</option>
And my helpers entry to use the map method:
Template.test.helpers({
elements: function () {
data = [
{ id: 1, type: "type" }
, { id: 2, label: "label" }
]
return data.map(function (item, index, array) {
var string = item.type || item.label
return { id: item.id, string: string }
})
}
})

Meteor collections: how to connect to different collections referring to each other?

I have two collections:
Contracts = new Mongo.Collection('contracts');
Reminders = new Mongo.Collection('reminders');
These are structured in the database more or less like this:
Contracts:
{
"id": "4432234",
"contract": "C-42432432",
"description": "Description of contract",
"counterpart": "Company name",
"status": "awarded"
},
etc.
Reminders:
{
"name": "Contract expiring",
"type": "expiring",
"contract": "C-42432432",
"reminderDate": "2015-06-01",
"urgency": 3
},
etc.
The "contract"-name here are referring to a "contract"-name in the contract-collection. We can ha multiple reminders connected to the same contract. Therefore I want them in two different collections.
To get the contract-data I use:
<template name="example">
{{#each contracts}}
{{description}}
{{/each}}
</template>
corresponding js:
Template.example.helpers({
contracts: function() {
return Contracts.find();
}
});
This works ok and the result in this instance is Description of contract.
But what do I do if I want to display the reminder-collection and get the corresponding data from the Contract-collection? In other words: I want to loop the reminder-collection and get the same output.
<template name="notworking">
{{#each reminder}}
{{description}}
<!-- Here I want the description from the Contract-collection -->
{{/each}}
</template>
corresponding js:
Template.notworking.helpers({
reminder: function() {
//?
}
});
You might be better off using Contracts._id to refer to a contract from the Reminders collection that way if the contract name and description change at some point you won't need to update all the related reminders.
Contract:
{
"_id": "tPN5jopkzLDbGypBu",
"contract": "C-42432432",
"description": "Description of contract",
"counterpart": "Company name",
"status": "awarded"
},
Reminder:
{
"name": "Contract expiring",
"type": "expiring",
"contractId": "tPN5jopkzLDbGypBu",
"reminderDate": "2015-06-01",
"urgency": 3
},
Then if you want to list reminders and show related contract information you'd have:
HTML:
<template name="remindersList>
{{#each reminder}}
Date: {{reminderDate}} Urgency: {{urgency}}
{{#with relatedContract}}
Description: {{description}} Counterpart: {{counterpart}} Status: {{status}}
{{/with}}
{{/each}}
</template>
JS:
Template.remindersList.helpers({
reminder: function(){
return Reminders.find(); // or whatever query you need to run
},
relatedContract: function(){
return Contracts.findOne({_id: this.contractId}); // 'this' will be the Reminder document
}
});
OR - if you want to keep your denormalized schema, then the relatedContract function would simply need to return Contracts.findOne({contract: this.contract})
I'm assuming you need to loop over each reminder inside the loop iterating over each contract :
<template name="contracts">
{{#each contracts}}
<p>{{description}}</p>
{{#each reminders}}
<p>{{description}}</p>
{{/each}}
{{/each}}
</template>
The current data context when evaluating the reminders will be the currently iterated over contract, so we can access its contract name using this.contract.
As a result you simply need to return every reminders document having the same contract name.
Template.contracts.helpers({
reminders: function(){
return Reminders.find({
contract: this.contract
});
}
});
https://atmospherejs.com/reywood/publish-composite
This package provides flexible way to publish a set of related documents from various collections using a reactive join. Hope it helps.

HandlebarsJS How to get last item of array

I want to fetch the last item of my JSON file. So I took a look at Getting the last element from a JSON array in a Handlebars template and tried to implement it. So far it gives me the number of the last entry but I need the options as well but dont know how to do it?
This is from the example mentioned
Handlebars.registerHelper("last", function(array, options) {
return array[array.length-1];
});
I tried to do:
Handlebars.registerHelper("last", function(array, options) {
if (array[array.length-1]) return options.fn(this);
return options.inverse(this);
});
My JSON files structure is:
releases: [{
"title" : "some title",
"releaseDate" : "2014-08-04"
},
"services": [{
"name" : "spotify",
"link" : "some link"
},
{
"name" : "itunes",
"link" : "some link"
}]
]
so my Handlebars template looks like:
{{#each releases}}
{{#last releaseDate}}
{{#each services}}
{{#equal name "Spotify" }}
{{/equal}}
{{#equal name "Itunes" }}
{{/equal}}
{{/each}}
{{/last}}
{{/each}}
But its not working, it displays an empty DIV
please help?
Handlebars already has #first and #last pseudo-variables. See docs on iterations and built-in helpers.
Example use case:
textArray = ["First", "N-1", "Last"]
<span>{{#each textArray}}{{#if #last}}{{this}}{{/if}}{{/each}}</span>
Result: <span>Last</span>
I would use an iterator helper for this.
Handlebars.registerHelper('layoutReleases', function (rows, options) {
var buffer = [], lastRow;
if (rows && rows.length > 0) {
lastRow = rows[rows.length-1];
buffer.push(options.fn(lastRow));
}
return buffer.join('');
});
Template:
{{#layoutReleases releases}}
{{releaseDate}}
{{#each services}}
{{#equal name "Spotify" }}
{{/equal}}
{{#equal name "Itunes" }}
{{/equal}}
{{/each}}
{{/each}}

Resources