94

I'm using Handlebars templates and JSON data is already represented in [Object object], how do I parse this data outside of the Handlebars? For example, I'm trying to populate a JavaScript variable on the page through a handlebars tag, but this doesn't work.

Any suggestions? Thank you!

EDIT:

To clarify, I'm using ExpressJS w/ Handlebars for templating. In my route, I have this:

var user = {}
user = {'id' : 123, 'name' : 'First Name'}

res.render('index', {user : user});

Then in my index.hbs template, I now have a {{user}} object. I can use {{#each}} to iterate through the object just fine. However, I'm also using Backbonejs and I want to pass this data to a View, such as this:

myView = new myView({
   user : {{user}}
});

The problem is that {{user}} simply shows [Object object] in the source. If I put it in console.log I get an error that says 'Unexpected Identifier'.

JShobbyist
  • 532
  • 3
  • 9
  • 23
dzm
  • 22,844
  • 47
  • 146
  • 226
  • You'll have to elaborate on "doesn't work." Can you provide a [relevant snippet of code](http://sscce.org/) and a description of what you're expecting instead of `[Object object]`? If you're simply trying to see the object's keys/values, you'll want to use `console.log` with a debugger or [`JSON.stringify`](http://caniuse.com/json). – Jonathan Lonowski Apr 19 '12 at 16:53
  • Console.log shows [Object object] also. I'll update post to explain better. – dzm Apr 19 '12 at 16:57

10 Answers10

196

When outputting {{user}}, Handlebars will first retrieve the user's .toString() value. For plain Objects, the default result of this is the "[object Object]" you're seeing.

To get something more useful, you'll either want to display a specific property of the object:

{{user.id}}
{{user.name}}

Or, you can use/define a helper to format the object differently:

Handlebars.registerHelper('json', function(context) {
    return JSON.stringify(context);
});
myView = new myView({
    user : {{{json user}}} // note triple brackets to disable HTML encoding
});
Jonathan Lonowski
  • 121,453
  • 34
  • 200
  • 199
  • 17
    it should be: {{{json user}}}, otherwise the json string will be encoded. – Jim Liu Jun 04 '14 at 02:22
  • Thank you, this is perfect. For Express users: `app.set('view engine', 'hbs'); var Handlebars = require('hbs');` – Oneiros May 04 '15 at 15:20
  • 4
    Works great. Also for [express-handlebars](https://github.com/ericf/express-handlebars) users: `var exphbs = require('express-handlebars'); app.engine('handlebars', exphbs({ helpers: { json: function (context) { return JSON.stringify(context); } } }));` – JayChase Nov 29 '15 at 04:51
  • 4
    Or just include the helpers when you render. `res.render('index', { var1: 'some value', helpers: { json: function (context) { return JSON.stringify(context); } });` – Derek Soike Jun 09 '16 at 21:15
  • Worked like a charm! How neat. – buycanna.io Mar 03 '18 at 09:10
  • What if user is created with new User(...) ? JSON.stringify() will lost all code from the User class/prototype, and leave you with a plain object. How to pass an Object as is ? – acmoune Apr 19 '18 at 20:41
  • This can be required when you are passing that object (user in this case) to JavaScript... – acmoune Apr 19 '18 at 20:48
  • 1
    @acmoune Going over the network, from server to client, the object has to be serialized into a data format. So sending it as it is in memory isn't strictly possible. Though, you may be able to share the definition of the `User` type and reconstruct the instance for the client – `user : new User({{{json user}}})`. – Jonathan Lonowski Apr 19 '18 at 23:45
  • @JonathanLonowski, You are right, I would have prefer to be able to do `var data = JSON.parse({{user}})` or simply `var data = {{user}}`, but it is just impossible. – acmoune Apr 20 '18 at 08:32
16

You can simple stringify the JSON:

var user = {}
user = {'id' : 123, 'name' : 'First Name'};
// for print
user.stringify = JSON.stringify(user);

Then in template print by:

{{{user.stringify}}};
nguyên
  • 5,156
  • 5
  • 43
  • 45
  • 1
    The answers above are splendid. I actually encountered an issue when rendering the JSON string in the view because i had an unescaped quote, This answer solved that https://stackoverflow.com/a/22105906/7998284 – hazelcodes Apr 09 '18 at 10:26
7

I'm using server-side templating in node-js, but this may apply client-side as well. I register Jonathan's json helper in node. In my handler, I add context (such as addressBook) via res.locals. Then I can store the context variable client-side as follows:

<script>
  {{#if addressBook}}
  console.log("addressBook:", {{{json addressBook}}});
  window.addressBook = {{{json addressBook}}};
  {{/if}}
</script>

Note the triple curlies (as pointed out by Jim Liu).

Community
  • 1
  • 1
Jeff Lowery
  • 2,492
  • 2
  • 32
  • 40
5

You can render the keys/values of a list or object in a Handlebars template like this:

{{#each the_object}}
  {{@key}}: {{this}}
{{/each}}
Sajjad
  • 430
  • 6
  • 17
3

Just improving the answer from @sajjad.

Adding a 'pre' tag will make it look a lot nicer.

<pre>
  {{#each the_object}}
    {{@key}}: {{this}}
  {{/each}}
</pre>
Nechar Joshi
  • 630
  • 1
  • 7
  • 14
2

In the Node Router - Stringify the response object. See below line.

 response.render("view", {responseObject:JSON.stringify(object)});

In HTML Script tag - user Template literals (Template strings) and use JSON.parse.

const json= `{{{responseObject}}}`;
const str = JSON.parse(json);

Worked like a charm!

markus
  • 5
  • 4
1

You are trying to pass templating syntax {{ }} inside a JSON object which is not valid.

You may need to do this instead:

myView = new myView({ user : user });

Terry
  • 14,099
  • 9
  • 56
  • 84
1

To condense (what I found to be) the most helpful answers...

JSON helper for handlebars (credit):

Handlebars.registerHelper("json", function (context) {
    return JSON.stringify(context);
});

JSON helper for express-handlebars (credit and I updated to newest conventions):

app.engine(
    "handlebars",
    exphbs.engine({
        defaultLayout: "main",
        helpers: {
            json: function (context) { 
                return JSON.stringify(context);
            }
        }
    })
);

And then on the templating side: {{json example}}

cf512
  • 71
  • 4
0

If you want more control over the output formatting you can write your own helper. This one has a recursive function to traverse nested objects.

  Handlebars.registerHelper('objToList', function(context) {
    function toList(obj, indent) {
      var res=""
      for (var k in obj) { 
          if (obj[k] instanceof Object) {
              res=res+k+"\n"+toList(obj[k], ("   " + indent)) ;
          }
          else{
              res=res+indent+k+" : "+obj[k]+"\n";
          }
      }
      return res;
    }    
    return toList(context,"");
  });

We used handlebars for email templates and this proved useful for a user like the following

{
  "user": {
    "id": 123,
    "name": "First Name",
    "account": {
      "bank": "Wells Fargo",
      "sort code": " 123-456"
    }
  }
}
Phil C
  • 962
  • 6
  • 17
0

You can do this:

 <div>
   {{toJSON this}}   
</div>

Define toJSON() in helper.js:

var helper = {};
module.exports = helper;
    helper.toJSON = function (context) {
        return JSON.stringify(context);
    };

In App.js:

const helper = require('./helper/helper');
app.engine('hbs', handlebars({
  layoutsDir: __dirname + '/views/layouts',
  extname: 'hbs',
  helpers: helper
}));
Shubham Verma
  • 8,783
  • 6
  • 58
  • 79