Meteor/Blaze Print Object as JSON - meteor

All,
I have on object in Meteor/Blaze. I tried this.
{{data}}
And it output
[object Object]
Is there any way I can get it to output JSON instead?

If you're looking to print a JSON object in JSON format in your Blaze view, you might wanna look at JSON.stringify() method.
Home.js [Helper example]
import './Home.html';
Template.home.helpers({
jsonPrint(jsonObject) { // with Latest Javascript ECMAScript 2015+
return JSON.stringify(jsonObject);
}
})
Home.html [Your Blaze view]
<template name="home">
<body>
<p>
JSON output:
</p>
<div class="code">
{{jsonPrint yourJsonObject}}
</div>
</body>
</template>
Reference:
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

I actually use a dev helper defined as below and which is in my own prototyping boilerplate:
Template.registerHelper("toJSON", function (object) {
return object ? JSON.stringify(object, null, 2) : null;
});

If you are trying to return values in that object, you will need to use JS dot notation so
{{foo.bar}}
where

Related

helpers result not passed to template in Meteor

I have a small helper which calculates an average by calling my method on the server side.
Template.replyDoc.helpers({
averageVote : function(userId){
var question = Template.parentData();
Meteor.call("averageVote",question._id,userId,function(error,result){
console.log('average: ' + result);
return result;
});
}
});
then I am trying to render my helpers results in my template:
<template name="replyDoc">
<div class="list-group-item">
AVERAGE:{{averageVote userID}}
</div>
</template>
average value is calculated properly as console.log works fine but i cannot see it rendered. Why is it the case and how I should solve it please?
I managed to find the answer;meteor methods inside helper
I used simple reactive-method and it worked.

How to build Meteor Templates at runtime?

Can I dynamically build templates on the server and send the result to clients? I found SpacebarsCompiler.compile() returns a string representing render function, but how to convert it to a template?
You could try this,
/**
* #contextObject the object you want to evaluate in your template
* #templateName the name of you template <template name="">
* return html rendered.
*/
function renderTemplate(contextObject, templateName){
return Blaze.toHTML(Blaze.With(contextObject, function() { return Template[templateName]; }));
}
I don't Im been using this in the client side I don't sure if will work on the server side but you could give it a try.
if you have a template html like
<template name="thisIsMyTemplateName">
<div>
{{name}}
</div>
</template>
then if you have an object like var myobject = { name : "my name" }
you could use the function like
myHtml = renderTemplate(myobject, "thisIsMyTemplateName");
you will get in return the plain html that you could append or do whatever you want like
$(document).append(myhtml);

Pass data to a dynamic template

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.

Why is 'this' in a Meteor Template onRendered Function undefined?

I'm using meteor 0.6.4. The problem i have is that the data context when rendering a template is sometimes undefined, so that, 'this' object is a reference to Window:
Template.task.time_left = function(){
debugger;
var nDate = this.due_date.getTime();
Exception from Deps recompute: TypeError: Cannot call method 'getTime' of undefined
The html code is wrapped inside an {{each}} handlebars statement:
<template name="tasks_lists">
{{#each tasks_list}}
...
{{#each task}}
{{> task}}
{{/each}}
...
{{/each}}
</template>
<template name="task">
...
<div class="text">{{due_date}}</div>
...
</template>
I read that this bug was solved in an earlier version of Meteor. What can I do to aviod the function being called with 'this' as Window.
You should use template.xxx.helpers instead, ie:
Template.task.helpers({
nDate: function() {
return this.due_date.getTime();
}
});
When you use it within helpers, this is the data context.
I used 'helpers' function and I have the same problem. 'this' object is sometimes the window object:
Template.task.helpers({
...
'time_left': function(){
debugger;
var nDate = this.due_date.getTime();
...
When using any of the three Meteor template callback functions, including the onRendered function, the this object is actually a template instance object. Although it is possible to retrieve the data context of the template through this object, it is recommended that you reference the template data context through the use of the Template.currentData() function. The documentation for this function can be found here.
The this inside a template helper will always points to window object.
You can access the data context in Template.rendered() or the event handler function. In the event handlers, it is passed as a second argument as function( event, template ), where the template is the current template object.
However I suggest you to use the template instance functions such as find(), findAll(), firstNode(), lastNode() rather than data context.
Template.task.rendered = function() {
if( !this.window ){ //check that 'this' is not a 'window' object
var el = this.find( 'div.text' ); // the div that holds due_date
//do something
}
}

Meteor: Passing more than one value to a template

I want to create a template/js combo similar to the ones below. What I would like is to have two variables available to the 'collection' template
<template name="collection">
Title: {{title}}
<UL>
{{#each items}}
{{> item}}
{{/each}}
</UL>
</template>
<template name="collection_items">
<LI>{{item_title}}</LI>
</template>
Where the javascript function would be something like:
Template.collection.data = function() {
var record = Record.findOne({whatever:value});
return { title: record.title, items: record.items }
}
I've tried using Handlebars' {{#with data}} helper and return an object as above, but that just crashed the template. I've tried creating a 'top level' function like:
Template.collection = function () {... }
but that also crashed the template.
What I'm trying to avoid is having two separate functions (one Template.collection.title, and one Template collection.items) where each of them calls a findOne on the Record collection where really its the same template and one call should suffice.
Any ideas?
Template.collection = function () {... }
Template.collection is not a function, it's an instance and thus an object.
You can type Template.collection in the console to see something essential as well as Template.collection. and autocomplete that to see its methods and fields.
For a #with example, the Todos indeed doen't seem to contain one as you have outlined in your comments. So, an example use of it can be found here:
https://github.com/meteor/meteor/blob/master/packages/templating/templating_tests.js#L75
https://github.com/meteor/meteor/blob/master/packages/templating/templating_tests.html#L92
Here is another example that I tried that works on both the current master and devel branch:
<head>
<title>test</title>
</head>
<body>
{{> hello}}
</body>
<template name="hello">
{{#with author}}
<h2>By {{firstName}} {{lastName}}</h2>
{{/with}}
</template>
And the JS part of it:
if (Meteor.is_client) {
Template.hello.author = function () {
return {
firstName: "Charles",
lastName: "Jolley"
};
};
}
Any specific reason why you're hoping to avoid two functions?
From your code sample I see one issue: the first template is calling a second template with this line:
{{> item}}
But your second template is not called 'items'. I believe that your second template should be called this way:
<template name="item">
Seems that it would be simple enough to have helper functions for the first and the second. Although I haven't gotten it to work with my own code, I believe the second helper function would want to use the 'this' convention to refer to the collection you're referring to.
Cheers - holling
Tom's answer is correct. I want to just chime in and add that in my scenario the reason why #with was failing was because due to the 'reactive' nature of meteor my first call to load the model resulted in 'undefined' and I didn't check for it. A fraction later it was loaded ok.
The moral is to do something like
var record = Record.findOne({whatever:value})
if (record) {
return record;
} else {
// whatever
return "loading"
}

Resources