How to display a nested array in a template - javascript

I'm trying to iterate in a array nested in an other array.
My collection data :
"roles" : [
{
"id" : 126987,
"name" : "Ergonomic Wooden Fish",
"containers" : [
{
"id" : "2654213845" ,
"name" : "FirstCont",
"rights" : [
{
"id" : "54684213",
"name: "FirstRight"
}
]
}
]
}
]
JS/Helpers
Template.myTemplate.helpers({
'roles': function() {
return Roles.find({});
}
});
HTML
<template name='myTemplate'>
{{#each roles}}
{{id}}
{{name}}
{{#each containers}}
{{name}}
{{/each}}
{{/each}}
</template>
I can display name and id from roles, but not name from containers.
I try to visualize the object back but I can't.
What am I doing wrong?

create another helper containers.
containers: function(){
return this.containers;
}
and then keep your template as it is.
<template name='myTemplate'>
{{#each roles}}
{{id}}
{{name}}
{{#each containers}}
{{name}}
{{/each}}
{{/each}}

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}}

Pass argument to collection in meteor reactive-table

I am using package aslagle:reactive-table
I want to pass an argument to the collection option of the reactive table
I have checked this also Meteor Reactive Table Helper Arguments but the comments on the post didn't help.
Html Code:
{{#each staffCode}}
{{> reactiveTable collection=collectionDetails settings=settingsResult}}
{{/each}}
Helper:
collectionDetails: function(staffCode){
return someCollection.find({staff_code: staffCode});
},
settingsResult: function(){
return {
rowsPerPage: 20,
showFilter: false,
showNavigation: 'auto',
fields: [
{
key: 'some_key', label: 'Some Label' ,
}
]
}
}
So far I tried putting
{{#each staffCode}}
{{> reactiveTable collection=collectionDetails ../code settings=settingsResult}}
{{/each}}
But this doesn't work and gives the following error in the terminal
Can't have a non-keyword argument after a keyword argument
Those who have the same issue, I have solved the problem, here's the way I approached it.
{{#each staffCode}}
{{#with collectionDetails code}}
{{> reactiveTable collection=this settings=settingsResult}}
{{/with}}
{{/each}}

Saved an object's id in a Meteor.user field, recalled the id in a template, how can i display the object's data instead of the id?

I have a collection of objects called Categories in a list. in my html, each category object is a list item and this category object has other objects in it, these are the category id, name and an array of posts that belong to that category. see image.
On each Category list item is a button that the user can click, this then saves the category id in a Meteor.user field called name.
<template name="CategoriesMain">
<ul>
{{#each articles}}
<li>
<h2>{{name}}</h2>
<button type="button" class="toggle-category">Add to User Field</button>
</li>
{{/each}}
</ul>
</template>
to achieve this i have this in my helper
Template.CategoriesMain.events({
'click .toggle-category': function(e){
//take the category id on click
var ob = this._id;
//make it into array
var id = $.makeArray( ob );
e.preventDefault();
Meteor.call('addingCategory', id, function(error, user){ console.log(id)});
},
});
then in my methods.
Meteor.methods({
addingCategory: function(name) {
Meteor.users.update({
_id: Meteor.userId()
},
{
$addToSet: {
name: name
}
});
}
});
Each user has a timeline in which the saved category ids appear.
<template name="userTimeline">
{{#if currentUser}}
<div class="timeline-user">
<p>{{name}}</p>
</div>
{{/if}}
</template>
in the helper
Template.userTimeline.helpers({
name: function() {
return Meteor.user().name;
//this is what im experiment with to link the category id's in the timeline with the category ids from the Category collection but i'm not sure if im going the right direction.
var name = FlowRouter.getParam('_id')
return CategoryCollection.find({_id: id}).fetch();
}
});
My question is, instead of displaying the category ids, can somehow get the objects of those category id and i.e posts that belong in that category? i know i have to somehow link the id collected by the user with that of the category
EDIT
I have amended my meteor methods to declare "category" as an array like so:
Accounts.onCreateUser(function(options, user){
user.category = [];
return user;
});
Meteor.methods({
addingCategory: function(category) {
console.log(Meteor.userId());
Meteor.users.update({
_id: Meteor.userId()
},
{
$addToSet: {
category: category
}
});
}
});
this is what the Meteor.users looks like, take a look at the "category" field.
I have amended the following in my helper, which is throwing the error:
Template.userTimeline.helpers({
category(){
return CategoryCollection.find({ _id: { $in: this.category }}); // a cursor of categories
}
});
in which CategoryCollection is the collection holding the categories.
since i declared "category" as an array in my methods, i'm no longer changing each category id into an array as i was doing before, so i changed my template event to this.
Template.CategoriesMain.events({
'click .toggle-category': function(e){
var ob = this._id;
console.log(ob);
e.preventDefault();
Meteor.call('addingCategory', ob, function(error, user){ console.log(ob)});
}
});
my Publish has changed to this: i don't know whether here i should use $in ?
Meteor.publish(null, function() {
return Meteor.users.find({_id: this.userId}, {fields: {category: 1}});
});
my html has been changed to this:
<template name="userTimeline">
{{#if currentUser}}
<div class="timeline-user">
{{#each category}}
Count: {{count}}
Description: {{description}}
Link: {{link}}
{{#each posts}}
ID: {{id}}
Title: {{title}}
{{/each}}
{{/each}}
</div>
{{/if}}
</template>
You can show the categories related to a user by iterating over the array of category ids and using a helper to return the entire category object. Then inside that you can loop over the posts.
<template name="userTimeline">
{{#if currentUser}}
<div class="timeline-user">
{{#each categories}}
Count: {{count}}
Description: {{description}}
Link: {{link}}
{{#each posts}}
ID: {{id}}
Title" {{title}}
{{/each}}
{{/each}
</div>
{{/if}}
</template>
Then your helper:
template.userTimeline.helpers({
categories(){
if ( this.category &&
typeof(this.category) === "object" &&
this.category.length ){ // check to see if the list of categories is an array
return categories.find({ _id: { $in: this.category }}); // a cursor of categories
} else {
console.log(this.category);
return null;
}
}
});
Remember that the data context this for the userTimeline template is the Meteor.user() object so this.name is going to be the array of category ids in Meteor.user().name

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

Ember Data: preload relationships

What I'm trying to do is very basic but I'm having very little luck...
Simply enough, I don't want to display a chunk of HTML until a certain Ember Data model property is fully loaded.
As you can see from the jsfiddle, the parent model: App.Person gets loaded into the DOM and it also loads the 3 placeholders for its hasMany property belts.
It then executes the request to populate App.Belt and fills in the placeholders.
While this is usually ok, it makes a big mess of things when trying to build an SVG, for example. Since the surrounding <svg> tags will get appended to the DOM immediately and then some time down the track (once the asynchronous request returns data), the inner svg components will be added between the tags. This usually creates browser rendering errors.
TL;DR
In the example, how do I defer the <h3>...</h3> section of the template from being added to the DOM until the model data and its relationships (belts) are fully loaded? This way everything gets visually and physically added to the DOM at once.
The JS:
// Create Ember App
App = Ember.Application.create();
// Create Ember Data Store
App.store = DS.Store.create({
revision: 11,
//Exagerate latency to demonstrate problem with relationships being loaded sequentially.
adapter: DS.FixtureAdapter.create({latency: 5000})
});
// Create parent model with hasMany relationship
App.Person = DS.Model.extend({
name: DS.attr( 'string' ),
belts: DS.hasMany( 'App.Belt' )
});
// Create child model with belongsTo relationship
App.Belt = DS.Model.extend({
type: DS.attr( 'string' ),
parent: DS.belongsTo( 'App.Person' )
});
// Add Parent fixtures
App.Person.FIXTURES = [{
"id" : 1,
"name" : "Trevor",
"belts" : [1, 2, 3]
}];
// Add Child fixtures
App.Belt.FIXTURES = [{
"id" : 1,
"type" : "leather"
}, {
"id" : 2,
"type" : "rock"
}, {
"id" : 3,
"type" : "party-time"
}];
// Set route behaviour
App.IndexRoute = Ember.Route.extend({
model: function() {
return App.Person.find();
},
renderTemplate: function() {
this.render('people');
}
});
The HTML/HBS:
<script type="text/x-handlebars">
<h1>Application</h1>
{{outlet}}
</script>
<script type="text/x-handlebars" id="people">
<h3>Don't load this header until every belt defined in App.Person.belts is loaded</h3>
<ul>
{{#each controller}}
{{debugger}}
<li>Id: {{id}}</li>
<li>Name: {{name}}</li>
<li>Belt types:
<ul>
{{#each belts}}
<li>{{type}}</li>
{{/each}}
</ul>
</li>
{{/each}}
</ul>
</script>
The fiddle: http://jsfiddle.net/zfkNp/4/
Check for the controller.content.length and belts.isLoaded, See the jsfiddle for a solution.
<script type="text/x-handlebars" id="people">
{{#if controller.ready}}
<h3>Don't load this header until every belt defined in App.Person.belts is loaded</h3>
{{/if}}
<ul>
{{#each controller}}
{{debugger}}
{{#if belts.isLoaded}}
<li>Id: {{id}}</li>
<li>Name: {{name}}</li>
<li>Belt types:
<ul>
{{#each belts}}
<li>{{type}}</li>
{{/each}}
</ul>
</li>
{{/if}}
{{/each}}
</ul>
</script>
App.IndexController = Ember.ArrayController.extend({
content: null,
ready:function() {
return this.get('content.length')>0
}.property('content.length')
});

Categories