Aframe + Meteor - Add a conditional custom component to an entity - meteor

<a-gltf-model id='playerone' {{#if myplayer playerone}}entitymove{{/if}} src="#myMixBun"> </a-gltf-model>
Using Aframe in Meteor, I want to add the custom component “entitymove” if the value of myplayer is “playerone”.
The value of {{myplayer}} is “playerone” in main.html, so the variable is set correctly. But I get the Meteor error “A template tag of type BLOCKOPEN is not allowed here”.
If “entitymove” was a “class”, for instance, I think I could solve this with the following:
<a-gltf-model id='playerone' class={{#if myplayer playerone}}entitymove{{/if}} src="#myMixBun"> </a-gltf-model>
But since it’s a component, I am at a loss as to how to fix the syntax.

Assuming that this uses Meteor-Blaze templates you need to include the conditionals for DOM element attributes inside quotes/double quotes:
<a-gltf-model id='playerone' class="{{#if myplayer playerone}}entitymove{{/if}}" src="#myMixBun"> </a-gltf-model>
Readings:
http://blazejs.org/guide/spacebars.html

SOLVED
This is my original, which doesn’t work.
In main.js:
player = "player not active";
Template.hello.helpers(
counter() {......
// if player one
player = "playerone";
// if player two
player = "playertwo";
return { myplayer: player };
}
In main.html:
// This statement works
{{counter.myplayer}}....
<a-gltf-model id='playerone' class="{{#if counter.myplayer playerone}}entitymove{{/if}}" src="#myMixBun"> </a-gltf-model>
<a-gltf-model id='playertwo' class="{{#if counter.myplayer playertwo}}entitymove{{/if}}" src="#myMixBun"> </a-gltf-model>
I think there are 2 problems with this:
1) spacebars doesn’t seem to like the if statement with a comparison?:
{{#if counter.myplayer playertwo}}
It only allows true or false if statements?, such as:
{{#if counter.player1}}
2) My aframe custom component isn’t actually a class, so I can’t put the meteor #if statement inside the entity.
I changed the code to the following and it now works:
Changed main.js to:
playerone ="";
playertwo ="";
// if player one
playerone = "true";
playertwo = "";
// if player two
playerone = "";
playertwo = "true";
return { player1: playerone, player2: playertwo};
}
Changed main.html to:
// These statements work
{{#if counter.player1}}player1 is true{{/if}}
{{#if counter.player2}}player2 is true{{/if}}....
{{#if counter.player1}}
<a-gltf-model id='playerone' entitymove src="#myMixBun" ></a-gltf-model>
<a-gltf-model id='playertwo' src="#myMixBun" ></a-gltf-model>
{{/if}}
{{#if counter.player2}}
<a-gltf-model id='playerone' src="#myMixBun" ></a-gltf-model>
<a-gltf-model id='playertwo' entitymove src="#myMixBun" ></a-gltf-model>
{{/if}}

Related

'this' context in Meteor event is empty object

Template works fine (in terms of data being displayed), but event doesn't. Particularly odd because I have a different template with almost the identical code in which it works.
<template name="profile_sidebar">
{{#if opened}}
{{> profile_sidebar_contents}}
{{/if}}
</template>
<template name="profile_sidebar_contents">
{{#if dataReady}}
{{#unless equalsCurrentUsername profile.login}}
<span>
<a class="message-user"><i class="ion-chatbox"></i> Message</a>
</span>
{{/unless}}
{{/if}}
</template>
Template.profile_sidebar_contents.events({
'click .message-user': function(e,t){
// this is {}
// t.data is null
Session.set('selectedConversation', this._id);
Router.go('/messages');
}
});
Thank you!
Found a solution!
I wrapped the entire template in a {{#with profile}} ... {{/with}} block and then added the data I needed to be within the profile object returned in the helper. It seems as though the context of the event was empty object because the event target was not within a scope.
Elaborated below
I assumed that the context would default to an object which had as fields all helpers. Ex. I had
Template.profile_sidebar_contents.helpers({
profile: function(){ return something },
id: function() {return somethingelse }
});
and I expected the context of this to be {profile: something, id: somethingelse}
but it seems that this isn't done and the context is empty. I moved it to be
Template.profile_sidebar_contents.helpers({
profile: function(){ return {profile:something, id:somethingelse} }
});
and then set {{#with profile}} ... {{/with}} and had access to the profile helper returned object, by which I could retrieve id by this.id and profile by this.profile

With clause changes keypath

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.

Is it possible to assign a parameter value within handlebars templates without using helpers?

I am trying to assign values within a template, the idea is to do something like this:
{{#if author}}
{{className = 'classA'}} <- trying to implement this line.
{{else}}
{{className = 'classB'}}
{{/if}}
<div class={{className}}></div>
Is it possible to do so without registerHelper?
I needed this solution solved in the same way the original poster expected. Therefore I created a helper function to do this for me.
function setVariable(varName, varValue, options){
options.data.root[varName] = varValue;
};
Contained within the options in the helper, is the data block, with the root of the helper variables.
I placed my variable within the root object, either assigning or overwriting with the value provided.
The helper in html looks a lot like this.
{{setVariable "thisVar" "Contents Here"}}
<div>
{{thisVar}}
</div>
You can do this with a partial.
partial:
<div class="{{classname}}">{{var1.author}}</div>
template:
{{#if author}}
{{> mypartial var1=. classname="classA"}}
{{else}}
{{> mypartial var1=. classname="classB"}}
{{/if}}
In this example I've passed the current scope as var1. I can't recall if the scope stays the same and the new variable is just added to it or if you have to pass the scope manually.
Small update from a helpful above answer. In Handlebars 4.x, it seems we have to get the variables from #root.
handlebars.registerHelper('assign', function (varName, varValue, options) {
if (!options.data.root) {
options.data.root = {};
}
options.data.root[varName] = varValue;
});
And then,
{{assign 'imageTag' 'drop-155'}}
{{#root.imageTag}}
{{#if author}}
<div class='{{ classA }}'></div>
{{else}}
<div class='{{ classB }}'></div>
{{/if}}
or try
<div class='{{#if author}} {{ classA }} {{else}} {{ classB }} {{/if}}'></div>
or maybe this
create a script
<script>
$(function(){
var class;
{{#if author}}
class = {{ classA }}
{{else}}
class = {{ classB }}
{{/if}}
var $specials = $('.special');
$specials.removeClass('special');
$specials.addClass(class);
})
</script>

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.

Handlebars helper for template composition

I have a Handlebar helper to invoke a template within a template,
the usage is this :
applyTemplate subTemplateId arg1=123 arg2="abc" ...
It is also possible to pass html content
{{# applyTemplate "tli" a=1 b="y"}}
... any content here will get passed to the sub template with {{content}}
{{/ applyTemplate }}
This jsFiddle illustrates how it works : http://jsfiddle.net/maxl/ywUjj/
My problem : I want the variables in the calling scope to be accessible
in the sub templemplate, in the jsFiddle, notice how {{topLevelVar}}
is not available.
Thanks
From this example i would say you can use fn to access the context in your helper method
http://yehudakatz.com/2010/09/09/announcing-handlebars-js/
applyTemplate: function(context, fn) {
for(var i=0, j=context.length; i < j; i++) {
buffer.push(fn(context[i]))
}
}
Where fn is the inner "template" part, and context the model that gets applied to it.
Starting from the solution on http://jsfiddle.net/dain/NRjUb/ we can achieve the same result but with inline templates as:
<script id="topLevel" type="text/x-handlebars-template">
{{# defTpl "test1"}}
La plantilla <b>diu</b> {{part}},{{../topLevelVar}}
{{/ defTpl }}
{{# each sub }}
Iplant-->{{eTpl "test1" part=this}}--fi plant<br>
{{/each}}
</script>
And registering the handlebars helpers like:
(function()
{
var h={};
Handlebars.registerHelper('defTpl', function(name, context){
// the subtemplate definition is already compiled in context.fn, we store this
h[name]=context.fn;
return "";
});
// block level /inline helper
Handlebars.registerHelper('eTpl', function(name, context){
if (!h[name]) return "Error , template not found"+name;
var subTemplate = h[name];
//if this isn't a block template , the function to render inner content doesn't exists
var innerContent = context.fn?context.fn(this):"";
var subTemplateArgs = $.extend({}, context.hash, {content: new Handlebars.SafeString(innerContent)});
return new Handlebars.SafeString(subTemplate(subTemplateArgs))
});
})();
And calling this with:
var _template = Handlebars.compile($('#topLevel').html());
$('body').append(_template({topLevelVar:123, content:"cascading",sub:[45,30,12]}));
Hope this helps :)
Add "../" before topLevelVar to access the parent context.
For example:
{{../topLevelVar}}
<script id="tli" type="text/x-handlebars-template">
<tr><td>{{a}}----> {{content}} <----- {{b}}</td></tr>
</script>
<script id="zaza" type="text/x-handlebars-template">
<table>
{{# applyTemplate "tli" a=1 b="y"}}<input type="text" value='a'>{{../topLevelVar}}{{/ applyTemplate }}
{{# applyTemplate "tli" a=2 b="z"}}<input type="text" value='b'>{{/ applyTemplate }}
</table>
</script>

Resources