How to use a javascript function inside a dust.js template? - data-binding

I'm using dust.js to do a client side templating. I would like to use a javascript function in my template, the function would get it's argument during templating i.e
Ex:
mytemplate = " <span> Hi getName({id}) </span>"
myjson = { id : 1 }
In this case, both the template and json-data are sent from server and templating happens on client side.
In the above example, I would get the 'id' from json data and want to display the name of user corresponding to that id.
I'm new to templating. I would like to know how this can be done using dust.js.
Thank you :)

This can be done with Dust.js by creating a script block within your template:
{! Dust template !}
<script type="text/javascript">
var userName = getName('{id|s|J');
// Do whatever you want with the username
</script>
Note, the |s|j, which is important for security filtering.
In your particular use case, however, it would probably be better to just send the user's name and id in the JSON:
{! Dust template !}
<span id="user-{id}"> Hi {name} </span>
// JSON
{
id: 1,
name: smfoote
}

Related

How to call dynamically helper in meteor

i have create one html help page like CMS and stored in database.
<content>
Contact us
</content>
In html file write this code
{{{helpPage}}}
Is it possible call dynamicUrl in html right now in <a> tag show
Contact us
I think the issue is that you want to be able to parse Spacebars template tags from a template string? If so,
Add carlevans719:dynamic-templates, then change
{{{helpPage}}}
to:
{{Template.dynamic template=dynamicTemplate}}
And in your template helpers, add:
dynamicTemplate: function () {
var content = getContentFromDB();
var template = new DynamicTemplate(content);
return template.name;
}
See: https://atmospherejs.com/carlevans719/dynamic-templates

Create/modify Meteor templates at runtime

I am wondering how to solve this problem:
I have a template which contains some text with some template helpers inside:
<template>Hello {{who}}, the wheather is {{weather}}</template>
Now I need to change the content of the template dynamically at runtime, while maintaining the helper functionality. For example I would need it like this:
<template>Oh, the {{weather}}. Good evening {{who}}</template>
The text changes and the helpers are needed at different positions. Think of an application where users can create custom forms with placeholders for certain variables like the name of the user who fills out the form. Basically, the content of the template is stored in a mongo document and needs to be turned into a template at runtime, or an existing template needs to be changed.
How to approach this? Can I change the contents of a template at runtime?
To solve this use case you need to use two techniques.
Firstly you need to be able to change the template reactivel. To do this you can use Template.dynamic. eg:
{{> Template.dynamic template=helperToReturnName [data=data] }}
See here: http://docs.meteor.com/#/full/template_dynamic
Now that you can change template, you need to be able to create new templates on the fly from you database content. This is non trivial, but it's possible if you're willing to write code to create them, like this:
Template.__define__("postList", (function() {
var view = this;
return [
HTML.Raw("<h1>Post List</h1>\n "),
HTML.UL("\n ", Blaze.Each(function() {
return Spacebars.call(view.lookup("posts"));
},
function() {
return [ "\n ", HTML.LI(Blaze.View(function() {
return Spacebars.mustache(view.lookup("title"));
})), "\n " ];
}), "\n ")
];
}));
That code snippet was taken from this article on Meteorhacks, and the article itself goes into far more detail. After reading the article you'll be armed with the knowledge you need to complete the task...
Just have a helper dynamically build the entire string (remembering that this refers to the current data context):
Template.foo.helpers({
dynamicString: function(switch){
if ( switch == 1) return "Hello "+this.who+", the wheather is "+this.weather;
else return "Oh, the "+this.weather+". Good evening "+this.who;
}
});
Then in your template:
<template name="foo">
{{dynamicString}}
</template>
Alternatively, just use {{#if variable}} or {{#unless variable}} blocks to change the logic in your template. Much, much simpler.
<template name="foo">
{{#if case1}}
Hello {{who}}, the wheather is {{weather}}
{{else}}
Oh, the {{weather}}. Good evening {{who}}
{{/if}}
</template>
You can always have a template helper that computes the necessary boolean variables (e.g. case1).

Meteor - TRIPLE template tag is not allowed in an HTML attribute error

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).

Handlebars : register helper based on template with 'body content'

I'm trying to implement some kind of 'macro' mechanism in a nodejs application using Handlebars (similar to the #bodyContent system in velocity.)
In my main template, I want to be able to write something like this :
{{#foobar who = user }}
<p>My body content</p>
{{/foobar}}
In a "views/helpers/foobar.html", I would have a file with a template, and some way to reference the "body content"
<p>Hello {{ who }}<p>
{{ bodyContent }}
<p>Bye !</p>
Based on the convention that the templates in "views/helpers" corresponds to a helper called with a single hash parameter, I want to automatically register them ; so I have something like this :
var helpers = "./views/helpers/";
fs.readdirSync(helpers).forEach(function (file) {
var source = fs.readFileSync(helpers + file, "utf8"),
helperName = /(.+)\.html/.exec(file).pop();
var helperTemplate = Handlebars.compile(source);
// We assume all helpers in the folder
// would take a hash as their first param
// We'll provide them with all the required context
Handlebars.registerHelper(helperName, function (options) {
var hash = options.hash || {};
// I want to somehow 'pass' the body Content ;
// The closest I have is 'this', but the markup is
// encoded, so I get a string with '<p>My body content</p>'
hash.bodyContent = options.fn(this);
console.log("Body Content", hash.bodyContent);
// Render the source as an handlebar template
// in the context of a hash
return helperTemplate(hash);
});
});
This does not work, as the tags are escaped, and so bodyContent is a String containing the markup, instead of the markup.
Is there a way I can fix my helper registration, or a built in mechanism in Handlebars to deal with this ?
Thanks
You need to use the {{{triple stashes}}} to unescape the HTML injection. So your template should look like:
<p>Hello {{ who }}<p>
{{{ bodyContent }}}
<p>Bye !</p>
You can read more here

Basic pattern: Populate a template with JSON from an external URL in Meteor

I am struggling to figure out the basic pattern for populating a template with data from a call to an external API in Meteor.
These are the elements in play
A fresh Meteor project, created by running meteor create monkeyproject
The URL of an external API that returns a JSON array. Let's say it's example.com/api/getmonkeys. It returns an array of monkeys, each with a different name.
A Handlebar template called monkeyTemplate with an {{#each}} loop. Let's say it's this:
<template name="monkeyTemplate">
{{# each monkeys}}
One of our monkeys is named {{name}}. <br>
{{/each}}
<input type="button" id="reload" value="Reload monkeys" />
</template>
What I want to happen
When the page loads fill monkeyTemplate with monkeys from our external URL.
When the user clicks the button, call the external URL again to reload the monkeys.
The question
What is a standard pattern for doing the above in Meteor? At the risk of cluttering up the question, I'll include some starting points, as I understand them.
We can populate the template with whatever we return from our Template.monkeyTemplate.monkeys function. How do we fill it with content from an external URL, given that the page will load before the external request is finished?
We can get our JSON by using Meteor.HTTP.call("GET", "http://example.com/api/getmonkeys", callback ). Where do we put this request, and what do we put into our callback function in this situation?
We can control what happens on the server side and what happens on the client side by using the Meteor.isServer/Meteor.isClient conditions, or by putting our code into files called client and server folders. What code needs to be on the server side vs. the client side?
We determine what happens when the button is clicked by attaching a function to Template.monkeyTemplate.events['click #reload']. What goes into our callback function in this situation?
I will refrain from cluttering up the question with my crappy code. I am not looking for anyone to write or rewrite an application for me—I am just looking for the guidelines, standard patterns, best practices, and gotchas. Hopefully this will be instructive to other beginners as well.
I'm not sure if this is the "standard" template, but it serves the purpose pretty well.
Set up two data helpers for the template, monkeys and loading. First one will display the actual data once it's fetched, the latter will be responsible for notifying user that the data is not yet fetched.
Set up a dependency for these helpers.
In created function of the template, set loading helper to true and fetch the data with HTTP call.
In the callback, set the template data and fire the dependency.
html
<template name="monkeys">
{{#if loading}}
<div>Loading...</div>
{{/if}}
{{#if error}}
<div>Error!</div>
{{/if}}
{{#each monkeys}}
<div>{{name}}</div>
{{/each}}
<div><button class="monkeys-reloadMonkeys">Reload</button></div>
</template>
js
var array = null;
var dep = new Deps.Dependency();
Template.monkeys.created = function() {
reloadMonkeys();
};
Template.monkeys.events({
'click .monkeys-reloadButton': function(e,t) {
reloadMonkeys();
};
});
var reloadMonkeys = function() {
array = null;
dep.changed();
HTTP.get('http://example.com/api/getmonkeys', function(error, result) {
if(!error && result) {
array = result;
} else {
array = 0;
}
dep.changed();
});
};
Template.monkeys.monkeys = function() {
dep.depend();
return array ? array : [];
};
Template.monkeys.loading = function() {
dep.depend();
return array === null;
};
Template.monkeys.error = function() {
dep.depend();
return array === 0;
};

Resources