I am using in a meteorjs application meteoric:ionic package with tap:i18n package for localization.Tap:i18n works fine when used in a html template, but I don't how to use it in a template like this:
{{#ionTabs style="ios"}}
{{> ionTab title="Welcome" path="tabs.one" iconOff="ios-home-outline" iconOn="ios-home"}}
{{/ionTabs}}
this doesn't work:
{{#ionTabs style="ios"}}
{{> ionTab title={{_ "welcome"}} path="tabs.one" iconOff="ios-home-outline" iconOn="ios-home"}}
{{/ionTabs}}
Its not possible to place handlebars inside other handlebars. You have to create a helper. This is quite annoying though since you will have to do it for each one. The issue is more meteoric isn't designed to work with i18n well yet:
Template.yourtemplate.helpers({
_title: function() {
return TAPi18n.__('welcome');
}
});
Where yourtemplate is the template containing the tabs.
Then you can use _title in the spacebars expression:
{{> ionTab title=_title path="tabs.one" iconOff="ios-home-outline" iconOn="ios-home"}}
Meteor is working on supporting statements in spacebars but its not yet released: See: https://meteor.hackpad.com/Blaze-lexical-scope-and-template-arguments-fZP806qG6xQ
More specifically to what you need: https://github.com/meteor/meteor/pull/4101
It should be in the next update as its already on devel. Then you could do:
{{> ionTab title=(_ "welcome") path="tabs.one" iconOff="ios-home-outline" iconOn="ios-home"}}
Related
everybody :) For example I have something like this:
{{> someCoolHelper
someParam1='someVal1'
someParam2='someVal2'
someParam3='SomeVal3'
someParam4=someAnotherHelper 'value param to this helper'
}}
So I have a function, that computes some value depending on parameter that can be passed in it. So how can I do this?
as you may read in a forum thread at meteor forum this is not possible by now in spacebars.
We began with a new package for chaining methods and arguments but its not released yet. What you could do is to use the WITH element like
Instead something like:
{{> someCoolHelper
someParam1='someVal1'
someParam2='someVal2'
someParam3='SomeVal3'
someParam4=someAnotherHelper 'value param to this helper'
}}
can be managed by:
{{#with someAnotherHelper 'value param to this helper' }}
{{> someCoolHelper
someParam1='someVal1'
someParam2='someVal2'
someParam3='SomeVal3'
someParam4=this
}}
{{/with}}
I don't like it, but sometimes necessary
Tom
P.S.: Or drop Spacebars and use React - you won't have such limitations there.
The placeholder solution until template sub expressions are available in Spacebars is to create an helper returning the adequate value in JS :
HTML
{{> myTemplate param1="A" param2=param2}}
JS
function someOtherHelper(param){
console.log(param);
}
Template.registerHelper("someOtherHelper", someOtherHelper);
Template.myTemplate.helpers({
param2: function(){
return someOtherHelper("B");
}
});
You can pass the output of a helper to another helper using parentheses. Pretty sure this is what you're after:
http://blazejs.org/guide/spacebars.html#Calling-helpers-with-arguments
You can also pass the output of a helper to a template inclusion or other helper. To do so, use parentheses to show precedence:
{{> Todos_item (todoArgs todo)}}
Here the todo is passed as argument to the todoArgs helper, then the output is passed into the Todos_item template.
Something I did in a recent project uses this functionality to allow conditional rendering of CSS classes to a component (stripped down for brevity):
# global helper to provide ternary operator
Template.registerHelper('ternary', (condition, resultTrue, resultFalse) => {
return condition ? resultTrue : resultFalse
})
# in my-template.js:
Template.My_template.helpers({
isComplete(score) {
return score === 1
}
})
# in my-template.html:
{{> some_component class=(ternary (isComplete this.score) "green" "red")}}
I've got this template named indexmade up of a bunch of partial templates.
<template name="index">
{{> jumbotron }}
{{> crew }}
{{> projects3 }}
{{> projects2 }}
{{> faq }}
{{> contact }}
</template>
Say that I've got JS code page-transitions.js that requires the DOM of jumbotron to be fully loaded in order to run.
It's not enough to simple do:
Template.index.rendered = function(){
// load page-transitions.js
};
I HAVE to do
Template.jumbotron.rendered = function(){
// load page-transitions.js here instead
};
This can get messy really quick because you need to be VERY specific about which partial templates need which JS code. And different templates could require the same JS code so you can run into a situation where you're loading the same JS code multiple times.
Is there a way to wait until the index template has completely rendered EVERYTHING, including all nested child templates, and then run the JS code?
Meteor.startup() doesn't work in this case either.
You can try a couple of things:
First, just use the classic jQuery.ready way. because, why not?
Meteor.startup(function() {
$(document).ready(function() {
// stuff.
});
});
Or you could try Tracker.afterFlush:
Meteor.startup(function() {
// I know each Template.template.rendered has its own afterFlush, but those
// computations are defined way before Meteor.startup so then, theoretically,
// the below code should be executed last even if it triggers recomputations here.
Tracker.afterFlush(function() {
// stuff.
});
});
With meteor updates up to 0.8 my old code stopped working.
Handlebars.registerHelper('getTemplate', function(id, context) {
return Template[id](context);
});
<template name="main">
....
{{{getTemplate templateName context}}}
....
</template>
//somewhere in other template
Template.main.context = {name:value};
This way I was able to render a custom template with custom data. Now I can't find the way to pass context to the dynamic template. With blaze both templateName and context is undefined. Any advice?
Meteor >= 0.8.2
You can use the UI.dynamic helper render a template with a context which are both specified dynamically. For more details, check out this issue.
Meteor < 0.8.2
Both of these issues are addressed on this page in the meteor wiki.
Handlebars.registerHelper is now UI.registerHelper as seen here.
Examples of how to dynamically render templates are shown here.
update
Actually, given the requirements, a solution doesn't seem very obvious to me. If you are willing to use session variables to set the template name and context, AND only have one dynamic template in your main template. You could do something like this:
<body>
{{> main}}
</body>
<template name="main">
{{> getTemplate context}}
</template>
<template name="dogs">
<p>There are {{animals}} dogs!</p>
</template>
<template name="cats">
<p>There are {{animals}} cats!</p>
</template>
Session.setDefault('templateName', 'dogs');
Session.setDefault('templateContext', {animals: 10});
Template.main.getTemplate = function() {
return Template[Session.get('templateName')];
};
Template.main.context = function() {
return Session.get('templateContext');
};
This was brought up on the meteor-core list and #dgreensp, MDG core dev working on Blaze, opened Ticket #2007 - How to render a template to HTML with data so they definitely know about this and I'd expect a fix to land soon after 0.8.0.
He also included the following workaround:
var toHTMLWithData = function (kind, data) {
return UI.toHTML(kind.extend({data: function () { return data; }}));
};
The github ticket has further discussion and alternate code snippets that you may find useful.
I got error message when trying to run existing meteor project.
$meteor
=> Started proxy.
=> Started MongoDB.
=> Errors prevented startup:
While building the application:
client/coinmx.html:169: TRIPLE template tag is not allowed in an HTML attribute
...title="Totals: {{{get...
^
In Meteor 0.8, it's possible to return a Javascript object which is directly rendered into HTML attributes versus earlier versions, where you had to render it yourself.
Old version:
<input name={{name}} title={{title}}>
helpers:
Template.foo.name = "fooName";
Template.foo.title = "fooTitle";
New version:
<input {{attributes}}>
helpers:
Template.foo.attributes = {
name: "fooName",
title: "fooTitle"
};
All of these can be functions, and reactive, etc. Because the object is rendered directly into attributes, there is no need for you to SafeString some manually rendered content as before. This is the recommended way to go if need to render HTML attributes.
See also the following for how conditional attributes work under this scheme:
https://github.com/meteor/meteor/wiki/Using-Blaze#conditional-attributes-with-no-value-eg-checked-selected
The error is pretty much explanatory: you cannot use {{{something}}} inside a HTML attribute, you need to use {{something}} instead. Depending on what the something is (it's not known from your question as you didn't provide the code), that's either all you need to do, or you can achieve similar functionality by returning new Handlebars.SafeString("result") from your helper instead of just "result". However, if you do, you need to be super sure that the thing you'll return won't break the HTML structure.
Hugo's answer above gave me the missing piece I needed for the same issue-- triple stashes in 0.8 no longer supported. Here is an example that hopefully helps.
Where you might have had {{{resolve}}} in your template, you would now do:
<template name='thing'>
<ol>
{{#each all}}
{{resolve}}
{{/each}}
</ol>
<template>
The helper code then makes use of Spacebars.SafeString which looks to be preferred with Blaze:
Template.thing.helpers({
all: function () {
return Things.find();
},
resolve: function () {
var result = "<li>";
for (var i = 0; i < this.arrayOfClassNames.length; ++i)
result += <'div class='" + this.arrayOfClassNames[i] + "'></div>";
result += "</li>";
return new Spacebars.SafeString(result);
}
});
The key here is to return the 'new Spacebars.SafeString(result)' to wrap your HTML (which must be well formed).
According to this blog post, I should register a helper to better debug handlebars templates, but is not working:
ReferenceError: Handlebars is not defined
So, how can I {{debug}} in Meteor/handlebars?
This is the helper function I use for debugging in my own projects:
Template.registerHelper("debug", function(optionalValue) {
console.log("Current Context");
console.log("====================");
console.log(this);
if (optionalValue) {
console.log("Value");
console.log("====================");
console.log(optionalValue);
}
});
You can then call it in your templates with {{debug}} and it displays the context you are currently in. Read more at http://docs.meteor.com/#/full/template_registerhelper.
In Meteor 0.4.0 you register handlers like this:
Template.myTemplate.helpers({
helper: function () {
// some code here
console.log(arguments);
}
});
There is no need to call Handlebars directly.
Make sure that you register your helper in client (or shared) meteor code.
Handlebars.registerHelper('helper', function() {
// Do stuff
});
This should be callable via {{helper}} in your templates.
For the sake of completeness: you can also use
Template.registerHelper('helper', helperFunc);
instead of Handlebars.regsterHelper('h',f);
A small reason this is better is that then your app won't need that much refactoring if you decide somewhere down the road that you want to use something else instead of Handlebars(i.e. Spacebars, the real name of meteors adaption) like jade for meteor.
This is really a comment to the accepted answer. Looking forward to one day hit 50 rep.