What does ".." do in an Meteor Spacebars statement? - javascript

I have a handlebar statement which passes a userid to a helper. I am unsure how this works. The handlebar {{#if isowner ..}} has .. what is passed here as parameter to the helper funktion?
<template name="test">
...
<table class="table table-hover table-striped">
{{#each tester}}
<tr><
<td>{{#if isowner ..}}
<i class="fa fa-trash removeUser"></i>
{{/if}}
</td>
</tr>
{{/each}}
</table>
...
</template>
Template.test.helpers({
'isowner':function(parent){
return parent.userId === Meteor.userId();
}
});
Obviously this is only true when the userid's are identical. Meteor.userId() is the current user on the client side. So which userid is passed to parent?
Sure, the name speaks for its self. It must be one level above - but what is this technically? Where does .. go?

.. returns the data context of the parent (enclosing) template or structure -- I rigged up a very simple MeteorPad here that you can maybe play around with to see how it works.
In your case, I think it's probably returning the data context for the test template. You can console.log(parent) in your helper to inspect that object and get a bit more info:
Template.test.helpers({
'isowner':function(parent){
console.log(parent);
return parent.userId === Meteor.userId();
}
});
You can find more information about how the .. is resolved and how it can be used in the spacebars readme.

Related

How Do I Use a Meteor Template Helper to Edit a Value Passed as a Parameter in Iron-Router?

How do I use a template-helper to edit the value of the parameter I passed into a route created using the pathFor method of iron-router???
I have this template-helper:
Template.registerHelper('slugify', function(obj){
return _.slugify(obj);
});
in my .html file I have this:
{{#each menuItemsFromDB}}
{{#each arrayOfMenuItems}}
<a class="item category" href="">
{{this}}
</a>
{{/each}}
{{/each}}
The {{this}} in the above code returns a string, the name of the category.
Because I have registered a template helper, I can SLUGIFY this category by:
{{slugify this}}
and then I have this route:
this.route('List',{
path: '/list/:category_slug',
template: 'list',
controller: 'ListController'
});
I can link to this route and pass a parameter to this route by:
{{pathFor 'List' category_slug='the-value-i-passed'}}
But that would be hard-coding it which cannot achieve the desired result I want.
I want it to be dynamic by using the 'slugify' template helper and iron-router's pathFor method and using the value of {{this}}.
What I'm trying to achieve is something like this although this code below doesn't work:
{{pathFor 'List' category_slug={{slugify this}} }}
What's the work around to achieve what I'm 'trying' to achieve with the above line????
I was hoping I can do something like:
{{pathFor 'List' category_slug=slugify(this) }}
or
{{pathFor 'List' category_slug='{{slugify this}}' }}
Long story short, what you're looking for is not yet implemented using the current syntax, although it's part of the Handlebars standard implementation, upon which Meteor Spacebars is based.
For the moment, you have to create a separate helper that slugifies your input and call it within pathFor.
JS
Template.myTemplate.helpers({
slugified: function(){
return _.slugify(this);
}
});
Spacebars
{{pathFor 'List' category_slug=slugified}}
Note that Handlebars sub-expression support is planned in a near future and might even make its way to the next version of Meteor according to this PR : https://github.com/meteor/meteor/pull/4101

Meteor currentUser

Using the node.js framework Meteor -
how come the currentUser variable is defined in a template such as here:
<template name="main_template">
<div class="container">
{{#if currentUser}}
{{> add_player_form_template}}
{{/if}}
</div>
</template>
but when I call currentUser from the console, it's undefined:
however, Meteor.userId is defined:
why is this?
{{ currentUser}} is a helper in the main_template template.
In your client Javascript you'll need to define that helper method. Something like:
Template.main_template.helpers({
currentUser: function() {
return Meteor.userId();
}
})
This may help too http://docs.meteor.com/#/basic/templates.
{{ currentUser }} is a template helper that simply calls Meteor.user().
In the console, you need to call Meteor.user().

Models, naming, and this

While running through the starter tutorial on EmberJS' site, a few things have me a little confused now.
One thing to note immediately is that I decided to use the ember 1.9.0beta4 with handlebars 2.0.0 instead of 1.8.1 / 1.3.0 included in the starter pack.
First the code included in the screencast:
app.js
App.Router.map(function() {
this.resource('about');
this.resource('posts');
this.resource('post', {path: ':post_id'})
});
App.PostsRoute = Ember.Route.extend({
model: function() {
return posts;
}
});
and
index.html
{{#each model}}
<tr><td>
{{#link-to 'post' this}}
{{title}} <small class='muted'>by {{author.name}}</small>
{{/link-to}}
</td></tr>
{{/each}}
This works exactly as expected and the requested post appears when clicked.
However, because I'm using 1.9.0, the preceding code produces a deprecated warning for {{#each}}, telling me to use {{#each foo in bar}} instead. I understand why this appears and agree the verbosity helps show exactly what data is being looped through.
So I change the line {{#each model}} to {{#each post in model}} and every bit of data disappears... I then try to change the code to:
updated index.html
{{#each post in model}}
<tr><td>
{{#link-to 'post' this}}
{{post.title}} <small class='muted'>by {{post.author.name}}</small>
{{/link-to}}
</td></tr>
{{/each}}
Great! The title and author's name once again appear for each post. But clicking either post gives me an undefined id. I change {{#link-to 'post' this}} to {{#link-to 'post' this.id}}. Same result. I change it to {{#link-to 'post' post.id}}. The id is now included but when I click the link I get this error:
Error while processing route: post Assertion Failed: You used the dynamic segment
post_id in your route post, but App.Post did not exist and you did not override
your route's `model` hook.
My questions are:
What happens internally that forces the post. prefix if I simply include the post in code? To me I should be able to use either this or continue to not need any prefix.
After adding post in to the each statement, what happens to this? Why does it no longer refer to the same object?
How can models be named to make it easier to categorize? post in model should really be post in posts but I haven't found a way to name the data container.
What is causing the error now that I'm no longer referring to the model as this? How can it be remedied?
Your frustration and questions are exactly the reason why the first syntax is deprecated and only the each post in ... form will be supported. Hopefully this answers your questions, and please respond if you need clarification.
In your first example where you use each model, the scope of the block changes to a post, meaning this refers to the current post in the loop. When you the form each post in ..., the scope does not change. When it does not change, that means this is actually referring to the previous scope (prior to the loop). In your example, the previous scope is the array controller, not the post object.
This is related to question 1. With the each post in ... format, this refers to whatever it was outside of the each block. It's not that something happens to this, it's that something does not happen to this because the scope doesn't change.
For better naming I usually setup a property as an alias to the content in the array controller:
posts: Ember.computed.alias('content')
In your original example, when you supply the link-to helper with this, you're passing the full post object. From what you've tried, it looks like this is the one thing you didn't do:
{#link-to 'post' post}}
I will try to answer your questions in order:
When you say {{#each model}} you are looping through the posts (array) in the model, so every time through the loop this is referring to the current post. Therefore when you say {{title}} you are really saying {{this.title}} When you are more explicit by saying {{#each post in model}} then each iteration through the loop is no longer referring to this and instead refers to the variable you made called post
Like mentioned in #1 above, this no longer refers to each individual iteration. I understand how you are thinking that perhaps still being able to use this (alongside post) would be convenient, but think about the following scenario. What happens when you have a nested {{#each}}? Would the implicit this refer to the outer array or inner array? If you really don't feel like typing the extra post. you can always use the {{#with post}} handlebars helper that scopes post back to this See the following example here
If you have a property in your model or controller, you can absolutely loop through that property as in {{#each color in colors}} See here for a working example
Finally, the link-to should be {{#link-to 'post' post}}

In Meteor using #each, check if 'last' element in the collection reached

I'm iterating through a collection in Meteor using {{#each}} and I would like to know if I'm in the last element, as I can do in AngularJS while using ngRepeat with $last.
It could be used, for example to construct human readable enumerations like 'I like cats, dogs and dolphins' :
Template.myTemplate.helpers({
likedAnimals: function(){return ['dogs','cats','dolphins'];}
});
<template name='myTemplate'>
I like
{{#each likedAnimals}}
{{#if !$first && !$last}}, {{/if}}
{{#if $last}} and {{/if}}
{{this}}
{{/each}}
</template>
Is there any way to check this condition in Meteor?
If any of you are wondering how to do the same with collection cursors, there's a much simpler way thanks to handlebar-helpers package.
You could then use:
$mapped - will map $first, $last, and $index onto your cursor or array
combined with $last helper in your template like that:
{{#each $mapped myCursor}}
{{name}}{{#unless $last}},{{/unless}}
{{/each}}
PS: this also works with arrays
Using underscore.js :
Template.registerHelper('last',
function(list, elem) {
return _.last(list) === elem;
}
);
<template name='myTemplate'>
{{#each likedAnimals}}
{{#if last ../likedAnimals this}} I'm the last ! {{/if}}
{{/each}}
</template>
Worked with a reactive data source for me with meteor 1.1.0.1 (I don't know when Template.parentData() was introduced in meteor).
This isn't supported in meteor yet (version 1.0), but you can kind of add it yourself by doing something like this:
Template.myTemplate.helpers({
likedAnimals: function(){
var animals = ['dogs','cats','dolphins']
return animals.map(function(animal, index){
return {
name: animal,
isFirst: index==0,
isLast: index==animals.length-1
}
})
}
})
However, this does not play nice with reactivity (making it work properly with reactivity is much harder, which I guess is the reason why this isn't a built in feature yet), but if you return a simple array that's not dependent on any reactive data source, this should work fine.

Handlebars templates - Rendering data inside if statement

To the handlebars (version 1.0.0-rc.3) template I am passing two variables, one is the json and the other one is the string containing the current language on site.
self.template = template({ data: self.model, lang:self.lang });
Then inside my template file I am having issues with displaying lang variable inside the if statement. So the structure of my template is the following:
{{#each data}}
{{#if this.title}}
...some html...
<a class='links' href="{{../lang}}/work/{{this.id}}">View Project</a>
...some html...
{{/if}}
{{/each}}
I am unable to access the lang variable only inside the if statement and outside is being shown properly...
Please advise...
I've found a solution by creating a handlebars helper function:
Handlebars.registerHelper( 'language'
, function() {
return self.lang;
});
Then in the template I can use {{language}} where ever needed.

Categories

Resources