With clause changes keypath - ractivejs

I have the following template:
{{#each Posts}}
{{#with { Post: this } }}
<h2 on-click="doSomething">{{Title}}</h2>
...
{{/with}}
{{/each}}
When I click on the header and doSomething get called, I get "${{Post:Posts-0}}" in event keypath. But I need to get access to the post keypath: "Posts.0" to modify some of its properties. What is the right way to achieve that?

Using a {{#with { a: b } }} block for aliasing in Ractive has some limitations, as it's not true aliasing, it's simply creating an expression with an object literal. It's a needed enhancement to offer true aliasing with something like {{#each Post in Posts}} or {{#each Posts as Post}}.
As far as what you can do today, you can add the keypath to the with block:
{{#with { Post: this, keypath: #keypath } }}
And then either pass in:
<h2 on-click="doSomething:{{keypath}}">{{Title}}</h2>
Or access in the event via this.event.context.keypath. See http://jsfiddle.net/w0npbnrz/ for both of these in action.
You also could use {{#each Posts:p}} in which case you could get the keypath via 'Posts.' + this.event.index.p.

Related

Meteor Blaze display array

I have collections like this:
I want to iterate over object.questions.teema for example.
I have helper:
Template.game.helpers({
theGame: function() {
var theGame = Game.findOne({_id:"LhQmaZKW8eJNenyX9"})
console.log(theGame)
return theGame
}
});
and template:
<template name="game">
{{#with theGame}}
{{#each theGame.questions}}
{{teema}}
{{/each}}
{{/with}}
</template>
But it doesnt work, what is wrong with the template?
'#each theGame.questions' Will not work inside the #with, because you can access the 'theGame' object directly.
The point is when you try to get theGame object inside the #with it will return you undefined, because 'theGame' object does not have theGame property, Which you want to access inside #with block.
<template name="game">
{{#with theGame}}
{{#each questions}}
//Thie #each because you have nested array. As I can see in your console log.
{{#each this}}
{{teema}}
{{/each}}
{{/each}}
{{/with}}
</template>
What is {{teema}} supposed to be?
Regardless, as you can see from your console.log statement, {{theGame.questions}} returns another array. But that array returns objects. This is really hard to query for with Blaze.
The better solution would be to flatten it out so that your data is shaped like this:
questions: [
{
a: 'asdfkjah',
level: 'askdjfhal',
q: 'asdkfh',
teema: 'asdkfjh'
vaartus: 100
},
{
...
}
]
This way you don't have an array nested in an array. That will allow you to:
{{#with theGame}}
{{#each theGame.questions}}
{{this.teema}}
{{/each}}
{{/with}}
theGame.questions is an array (that you iterate over) of array of objects which have the teema key. So you still need to iterate over the 2nd level array, or define a specific item in that array before you can eventually reach the object with teema property.
Maybe something like:
{{#with theGame}}
{{#each questions}}
{{#each this}}
{{this.teema}}
{{/each}}
{{/each}}
{{/with}}
But it depends on why you have these 2-level arrays in the first place.

Pulling data from collection using Iron router

I have a small issue. The below code snippet works well if i directly dump it in the body tag
{{#each tasks}}
<ol> <li>Router Name: {{ routerName }}</li>
<li>Router Enable: {{Enable}}</li></ol>
{{/each}}
However, when I wrap it within a template and try call it via a route (iron router), it fails to show the query result.
<template name ='ManagementConfig'
{{#each tasks}}
<ol> <li>Router Name: {{ routerName }}</li>
<li>Router Enable: {{Enable}}</li></ol>
{{/each}}
</template>
Route.js:
Router.route('/ManagementConfig',{ name:'ManagementConfig' });
Everything apart from the above works well within the template and the route. Where am I going wrong?
Your ManagementConfig template don't have access to tasks object. You can fix this by creating a helper method and passing the data.
Template. ManagementConfig.helpers({
'tasks': function(){
//Change this to your task data
return Lists.find({}, {sort: {name: 1}});
}
});

Meteor #each #index passed to Dynamic Template?

I'm trying to pass down the index of an item from an {{#each}} loop into a dynamic template, but am lost on how to get it there (in a clean way).
Current code:
{{#each item}}
{{Template.dynamic template=type data=this}}
{{/each}}
With this, {{#index}} is not accessible in the dynamically loaded template.
I also tried using a template helper, but it doesn't appear the index is tracked in the context.
{{#each item}}
{{Template.dynamic template=type data=itemData}}
{{/each}}
Template.items.helpers({
itemData() {
// can't access index in here
return this;
}
});
Can anyone advise on how I can achieve this?
Thanks!
Solved this using the following pattern:
... Template.Items
{{#each items}}
{{>Template.dynamic itemConfig #index}}
{{/each}}
Template.items.helpers({
itemConfig(index) {
const data = this;
data.index = index;
return {
data,
template: this.type //this.type is where im storing my template name
};
},
});
Using the #index as a helper param, and then Blaze uses the object as a config for the dynamic template!
:)
EDIT: I found another solution. Does the same job, and I prefer how it looks.
{{>Template.dynamic template=type data=(templateData #index)}}
Where templateData is essentially the same helper from before but just returns data with an index prop.
{{#each item}}
{{Template.dynamic template=type index=#index}}
{{/each}}
You can use 'index' in dynamic template to access index

Meteor: Spacebars each parameter

I'm new to Meteor.js and have run into a problem.
I am passing in a user object to a profile template e.g.:
{
_id: "D8JpXRQskm3grykjg",
username: "foo",
profile: {communities: ["AkGCakz6mSgMb8qyS", "j8aB3i5iscrC4ehkA"]},
}
<template name="profile">
<h1> {{username}}: {{_id}} </h1>
<h3>Communities</h3>
<hr>
{{#each profile.communities}}
{{> communityItem}}
{{/each}}
</template>
The problem is I've already written a communityItem template that I am using elsewhere which accepts the communityName. Is there a way that I can write a helper function, passing in the communityIds list that would return a list of community names? I would like:
...
{{#each getCommunityNames(profile.communities)}}
{{> communityItem}}
{{/each}}
...
I could very well be approaching the problem the wrong way or not writing in a "Spacebars" fashion. Thanks!
sure you can:
Template.myTemplate.helpers({
getCommunityNames: function(commIds) {
var communities = Communities.find({_id: {$in: commIds}}).fetch();
return _.pluck(communities, 'name'); // returns ['Name 1', 'Name 2'];
}
});
Note, the syntax method param not method(param)
{{#each getCommunityNames profile.communities}}
{{>communityItem}}
{{/each}}

Meteor template: Pass a parameter into each sub template, and retrieve it in the sub-template helper

I am trying to figure out how to pass a parameter into a sub-template that is in an each block and use the parameter in the sub-template as well as sub-template helper. Here is what I tried so far:
template:
<template name="parent">
{{#each nodes }}
{{> child myParam}}
{{/each}}
</template>
<template name="child">
{{ paramName }}
</template>
js:
Template.parent.nodes = function() {
//return a list
};
Template.parent.myParam = function() {
return {"paramName" : "paramValue"};
};
Template.child.someOtherHelper = function() {
//How do I get access to the "paramName" parameter?
}
So far, it hasn't been working, and it seems somehow mess up my input node list also.
Thanks for help.
When you use {{> child myParam}}, it's calling the child template and associates myParam as current template data context, meaning that in the template you can reference {{paramName}}.
In someOtherHelper you could use this.paramName to retrieve "paramValue".
However, when you're using {{#each nodes}}{{> child}}{{/each}}, it means that you pass the content of the current list item (fetched from a LocalCursor or directly an array item) as the template data of child, and you can reference the list item properties using {{field}} in html or this.field in js.
What's happening here is when you call {{> child myParam}}, the myParam helper content OVERWRITES the current node item as template data, that's why it's messing your node list.
A quick (dirty) trick would be to simply extend the myParam helper so that it also contains the template data from the {{#each}} block.
Template.parent.helpers({
nodes:function(){
// simulate typical collection cursor fetch result
return [{_id:"A"},{_id:"B"},{_id:"C"}];
},
myParam:function(){
// here, this equals the current node item
// so we _.extend our param with it
return _.extend({paramName:"paramValue"},this);
}
});
Template.child.helpers({
someOtherHelper:function(){
return "_id : "+this._id+" ; paramName : "+this.paramName;
}
});
<template name="parent">
{{#each nodes}}
{{> child myParam}}
{{/each}}
</template>
<template name="child">
{{! this is going to output the same stuff}}
<div>_id : {{_id}} ; paramName : {{paramName}}</div>
<div>{{someOtherHelper}}</div>
</template>
Depending on what you're precisely trying to achieve, there might be a better approach but this one gets the job done at least.

Resources