Meteor pass a dynamic variable from template to helper - javascript

I'm working on a meteor project where I want to place an objects from the same collection in different divs depending on their properties. The easiest way to explain is probably to show a test case:
html
<template name="board">
{{#each rows}}
<div id="row-{{this}}" class="row">
{{#each columns}}
<div id="{{..}}-{{this}}" class="column column-{{this}} row-{{..}}- column">
{{>pins }}
</div>
{{/each}}
</div>
{{/each}}
</template>
<template name="pins">
{{#each pins}}
<div class = "pin" >{{this}}</div>
{{/each}}
</template>
js
Template.board.helpers({
rows: [
'top',
'middle',
'bottom'
],
columns: [
'left',
'center',
'right'
]
});
Template.pins.helpers({
pins:[
{name: 'test1', loaction: 'bottomcenter'},
{name: 'test2', loaction: 'topleft'},
{name: 'test3', loaction: 'bottommcenter'},
{name: 'test4', loaction: 'middleright'}
]
});
I'd like to place the pins in the correct div based on their location. Now I can of course manually write out every div in the html and a helper for each one (and will if there's no better solution), but I'm trying to figure out what the most efficient solution is.
I tried passing the location back to the helper function with the following code:
{{#each pins location="{{..}}{{this}}}}
and this
{{#each pins location="{{..}}{{this}}"}}
and running a function, But the tags after location= come through as {{..}}{{this}} instead of the values.
I also tried restructuring the data like this:
pins:{
bottomcenter: [{name: 'test1'}, {name: 'test3'}]
topleft:[{name: 'test2'}]
}
etc, and passing the parameter as a data context:
{{>pins {{..}}{{this}}}}
but that didn't seem to work either. Any help is appreciated!

your template should like:
<template name="pins">
{{#each pins}}
<div class = "pin" >{{this.name}} {{this.location}}</div>
{{/each}}
</template>
and the helper like this:
Template.pins.helpers({
pins: function() {
return [
{name: 'test1', loaction: 'bottomcenter'},
{name: 'test2', loaction: 'topleft'},
{name: 'test3', loaction: 'bottommcenter'},
{name: 'test4', loaction: 'middleright'}
]
}
});

I think I got it! The trick seems to be that you can't embed {{}} brackets in other {{}} brackets. So you use:
<template name="pins">
{{#each pins .. this}}
<div class="pin">
{{this.name}}
</div>
{{/each}}
</template>
.. and this get passed back to the helper function, and then you can search based on the results:
Template.pins.helpers({
pins: function(row,col){
var search = row+"-"+col;
var results = [];
var pinarr = [
{insert data here}
];
for(var i = 0; i < pinarr.length ; i++){
if(pinarr[i].location === search) {
results.push(pinarr[i]);
}
}
return results;
}
});
}

Related

How to reference more than one element in an handlebars helper block on node.js?

So, I have an object like this:
object = {
"group_1": [
{
"name": "Foo"
}
],
"group_2": [
{
"name": "Bar"
}
]
}
And in my hbs view I'm doing like this:
{{#each group_1}}
<p>{{name}}</p>
{{/each}}
{{#each group_2}}
<p>{{name}}</p>
{{/each}}
Is there any way of concatenating both and not repeating code? The solution would be something like this:
{{#each group_1 + group_2}}
<p>{{name}}</p>
{{/each}}
Any idea how to do this?
Handlebars itself does not support this.
But you can still do:
object.groups = object.group_1.concat(object.group_2);
{{#each groups}}
<p>{{name}}</p>
{{/each}}
Which seems to be a straightforward solution.
Alternatively you can put both your groups into an object and iterate over it like this:
let object = {
groups: {
'group_1': [
{
'name': 'Foo'
}
],
'group_2': [
{
'name': 'Bar'
}
]
}
};
{{#each groups}}
{{!-- you can refference group name as #key here --}}
{{#each this}}
{{name}}
{{/each}}
{{/each}}

Meteor dynamic category list

I would like to do the following. I would like to create a categories page that loads each category onto a picture. Then when a user clicks a category the parameter would show up on the url and it will search the database for photos based on that category. I will now demonstrate the code that I have.
Categories HTML File:
<template name="categories">
<div class="text-center light-container" id="categories-section">
<h1>Categories</h1>
<hr/>
{{#each categories}}
<div class="image-container">
<a href="{{pathFor route='categoryPage'}}">
<img class="freezeframe pics" src="images/app/sphere.jpg"/>
</a>
<h2><span>{{categories}}</span></h2>
</div>
{{/each}}
</div>
</template>
Categories JS File:
var categoryList = ['actions', 'animals', 'anime', 'art/design', 'cartoons/comics', 'celebrities',
'Emotions', 'Food/Drink', 'Games', 'History', 'Holidays', 'Memes', 'Movies', 'Music', 'Nature', 'News/Politics',
'Science', 'Sports', 'Technology', 'TV'];
Template.categories.helpers({
'categories':function(){
for(var i = 0; i < categoryList.length; i++){
console.log(categoryList[i]);
return categoryList[i];
}
}
});
Router JS File:
Router.route('/categories', {
name: 'categories',
template: 'categories',
fastRender: true
});
Router.route('/categories/:category', {
name: 'categoryPage',
template: 'categoryPage',
data: function(){
var category = this.params.category;
return GifsCollection.find({category: category});
},
fastRender: true
});
CategoryPage JS:
Template.categoryPage.helpers({
// Load 16 most recent ones
// When down arrow is click load another 16 more gifs
gifs: function() {
var category = this.params.category;
return GifsCollection.find({category: category}, {fields: {_id: 1, image: 1} });
}
});
Running the following code doesn't get me anywhere. I'm not sure which path to take. I can create a 'category' collection and load the helpers onto there or I can use sessions? but I'm leaning onto creating category collection however I'm pretty sure there is a much more efficient way.
Any feedback and code help would be greatly appreciated!!!
You have two small errors. One we already discussed in comments, regarding the helper. The other is in how you use the #each loop: inside of it you can just refer to this to get the string of your category.
Categories HTML File:
<template name="categories">
<div class="text-center light-container" id="categories-section">
<h1>Categories</h1>
<hr/>
{{#each categories}}
<div class="image-container">
<a href="/categories/{{this}}">
<img class="freezeframe pics" src="images/app/sphere.jpg"/>
</a>
<h2><span>{{this}}</span></h2>
</div>
{{/each}}
</div>
</template>
Categories JS File:
var categoryList = ['actions', 'animals', 'anime', 'art/design', 'cartoons/comics', 'celebrities',
'Emotions', 'Food/Drink', 'Games', 'History', 'Holidays', 'Memes', 'Movies', 'Music', 'Nature', 'News/Politics',
'Science', 'Sports', 'Technology', 'TV'];
Template.categories.helpers({
'categories':function(){
return categoryList;
}
});

Access an object's property names in a Blaze template

Say I have a helper that looks like this:
Template.profile.helpers({
info: {
Name: 'Bob Dinkleberg',
Age: 45,
Location: 'Earth, Milky Way'
}
});
I want to put this info in a <ul>. Here is some pseudo-code:
<template name="profile>
<ul>
{{#each}}
<li> {{key}}: {{property}} </li>
{{/each}}
</ul>
</template>
Forgive me if this is trivial, I am new to Meteor and Blaze, and I haven't been able to find a solution online.
If you want to loop through an objects properties and values as you requested, you can do it generic by:
Template.content.onCreated(function() {
this.properties = new ReactiveVar({
Name: 'Bob Dinkleberg',
Age: 45,
Location: 'Earth, Milky Way'
});
});
Template.content.helpers({
keys: function () {
return Object.keys(Template.instance().properties.get());
},
key_value_pair: function() {
return { key: this, value: Template.instance().properties.get()[this] };
}
});
and with this template
<body>
<h1>Property Loop</h1>
<ul>
{{> content}}
</ul>
</body>
<template name="content">
{{#each keys}}
{{> property key_value_pair }}
{{/each}}
</template>
<template name="property">
<li>{{key}}: {{value}}</li>
</template>
I prepared this MeteorPad for you which is a running example:
http://meteorpad.com/pad/24MGwbuMNCcXCC7EW/PropertyLoop
Cheers,
Tom
P.S.: It is not necessary to create the object as a ReactiveVar if there a never changes to its values. But by doing it as a ReactiveVar the form is als reactivly updated, when object content will change.
This will be helpful:
http://meteorcapture.com/spacebars/
You want to use {{#with}}.
<template name="profile">
<ul>
{{#with info}}
<li>{{Name}}</li>
<li>{{Age}}</li>
<li>{{Location}}</li>
{{/with}}
</ul>
</template>
While your helper code is correct:
Template.profile.helpers({
info: {
Name: 'Bob Dinkleberg',
Age: 45,
Location: 'Earth, Milky Way'
}
});
I personally like to make a habit of mapping the name of the helper to a function that returns something.
Template.profile.helpers({
info: function(){
return {
Name: 'Bob Dinkleberg',
Age: 45,
Location: 'Earth, Milky Way'
};
}
});
EDIT
Template.content.helpers({
info: function(){
var obj = {
Name: 'Bob Dinkleberg',
Age: 45,
Location: 'Earth, Milky Way'
};
var arrayOfObjects = [];
// creating an array of objects
for (key in obj){
arrayOfObjects.push({key: key, value: obj[key]});
};
console.log("This is the array of objects: ", arrayOfObjects);
return arrayOfObjects;
},
});
HTML:
{{#each info}}
{{value}}
{{/each}}

ReactiveJS templates : Iterating Over an Object , using array iteration

Im rewriting an angularjs directive ,moving all the markup from angular to reactiveJS, due to the poor dom performance of angularjs.
i have a simple a question about reactiveJS templating.
Template
{{#each dataTable:i}}
<li
{{#options.keysDisplayName:j}}
<span>{{dataTable[i][this]}}</span>
{{/each}}
</li>
{{/each}}
JS
var ractive = new Ractive({
el: 'details-table',
template: '#details-table-tmplt',
data: {
options: {
keysDisplayName : [ 'name', 'age']
},
dataTable : [
{name : 'dog', age:15, gender: 'f'},
{name : 'cat', age:15, gender: 'f'}
]
}
});
Im printing a table/list ,
I want to iterate on the each row in the dataTable , but only on the keys that present in options.keysDisplayName . ( so in this example , gender property wont be shown)
I guess im missing somthing basic in framework.
Thanks , much appreciated
Fix your template to:
{{#each dataTable:i}}
<li>
{{#each options.keysDisplayName:j}}
<span>{{dataTable[i][this]}}</span>
{{/each}}
</li>
{{/each}}
After fix the output will be:
dog15
cat15

scoping of an action helper within a handlebars #each loop

I've become confused about the scoping within an {{#each}} block.
If I have the handlebars script
<script type="text/x-handlebars">
{{#each vars}}
<button {{action foo}}> {{name}} </button>
{{/each}}
</script>
and I set my application controller as
App.ApplicationController = Ember.Controller.extend({
vars: Ember.ArrayController.create({
content: [
{ name: "Cow",
foo: function(){console.log("moo");}
},
{ name: "Cat",
foo: function(){console.log("meow");}
}
]
})
});
The script can see {{name}} just fine and puts it in as the title of the button as you'd expect, but action does not get bound to the foo functions defined within the array members.
Is there are way to do this that I'm missing, or do I need to refactor to make foo be defined directly within ApplicationController?
You can set up an event on ApplicationController and pass in the individual object and call the stored foo(). Inside of the {{#each vars}}...{{/each}} block you can use this to pass the actual object to the event handler.
JS:
App.ApplicationController = Ember.Controller.extend({
vars: Ember.ArrayController.create({
content: [
{ name: "Cow",
foo: function(){console.log("moo");}
},
{ name: "Cat",
foo: function(){console.log("meow");}
}
]
}),
doFoo: function(obj) {
obj.foo();
}
});
Handlebars:
{{#each vars}}
<button {{action doFoo this}}> {{name}} </button>
{{/each}}
JSBin example
Action in handlebars template not firing
This may be due to the root element, check this posting here for more information

Categories