20

I'm generating a handlebars view for express js framework, and I need to access the variables I pass to the view from inside a separate JavaScript file.

For example:

var foo = {{user.name}}

Someone got an idea? Helper?

Cœur
  • 37,241
  • 25
  • 195
  • 267
PokeRwOw
  • 609
  • 1
  • 6
  • 29

5 Answers5

25

The value of user.name needs to be output as a valid JavaScript expression if you want to include it in within a <script>, which will be reevaluating it as code.

Currently, if user.name is "john.doe" for example, the resulting script will be:

var foo = john.doe; // `john` is treated as an object with a `doe` property

The user.name at least needs to be in quotes so it's understood as a string value/literal.

var foo = "{{user.name}}";
// result
var foo = "john.doe";

You can also take advantage of JSON and JavaScript's similarities in syntax, outputting JSON that JavaScript can understand as an Expression, and will already include the quotes.

Handlebars.registerHelper('json', function (content) {
    return JSON.stringify(content);
});
var foo = {{{json user.name}}};
// result
var foo = "john.doe";

Note the triple {{{...}}} in the last example to disable HTML encoding, so you don't end up with:

var foo = &quot;john.doe&quot;
Jonathan Lonowski
  • 121,453
  • 34
  • 200
  • 199
  • Thanks you for your help ! I didn't saw anywhere this method : var foo = "{{user.name}}"; It's helped me a lot :) – PokeRwOw Jun 11 '15 at 00:20
  • I had `` where myJson was a pretty large object and seems like handlebars was unable to parse it. I could only get it working when I tried the solution I suggest in my answer – Drkawashima Sep 02 '16 at 17:55
  • this one also works for me : var foo = "{{user.name}}"; thnx! – Abdullah Alkurdi Jan 11 '19 at 04:24
  • 1
    It is possible to get the value from a *.js file? Or i have to set the value to an element attribute `data-my-value` and get it this way? – vik Aug 21 '19 at 18:51
  • Does this solution not work anymore? I've seen it elsewhere as well, but whenever I declare a variable assigned to {{{helper value}}} I get a syntax error with the first { as an unexpected token. How are people setting a variable equal to a value that has triple brackets in their client side javascript? – Matthew Wolman Apr 29 '20 at 20:43
18

Node can pass encoded JSON to the handlebars-view like this:

result.render('index', { 
  encodedJson : encodeURIComponent(JSON.stringify(jsonData))
});

The handlebars-view can decode and parse the json like so:

<script>
  var decodedJson = decodeURIComponent("{{{encodedJson}}}");
  var jsonObj = JSON.parse(decodedJson);
</script>

Since anything passed to a handlebars-view will basically be injected straight into HTML, you should always pass encoded json and let the view decode it.


I tried the other suggestions in this thread. But they injected unencoded JSON into the handlebars view and that always gave me parsing errors. I have no idea how people got that to work, since it seems like Handlebars will parse variables as plain text.

I have not read up on how the Handlebars parser works - but it seems to me the only safe option is to use encoded JSON, like how I suggest in my examples.

Drkawashima
  • 8,837
  • 5
  • 41
  • 52
  • encoding from the `render` function mangles my data into unusable `[object][object]` string. so i encode it via a view helper instead. additionally, using triple brackets `{{{` causes syntax error for me. double brackets works fine. all said, this solution manages to point me to the right direction. – RZKY Oct 22 '19 at 18:42
  • This works for me but it only works if the script tag is directly in the .hbs file. If I link in a script file from another folder it doesn't pick up on the encoded text. Do you know if it is possible to access the encoded text in a foreign script file? Accessing it in a – Matthew Wolman Apr 29 '20 at 21:14
1

I didn't know how to do this in a separate js file either. These answers led me in the right direction, so thank you! I ended up JSON stringifying the data on the server-side, before I passed it to the page via render. However, I still couldn't get the code to work in a separate js file - which is fine. My use case was for Materialize input form autocomplete.

node.js

// code is inside of a router.get block, therefore access to the response(res)

let customerData = {}
// add customer data with a loop, or whatever

const customers = JSON.stringify(customerData)

res.render('path/to/page', {
    customers
})

client-side js

// code placed within script tags of the handlebars file, not a separate js file

const customers = {{{customers}}}
crevizzle
  • 11
  • 2
1

Save as helper:

json: function (n: any) {
    return JSON.stringify(n)
},

Send:

<script src="/path/to/src" data="{{json data}}"></script>

Get:

const data= JSON.parse(document.body.querySelector('script[data]').getAttribute('data'))
Akif Kara
  • 442
  • 6
  • 14
0
var pageData = "{{pageData}}";
pageData = pageData.replace(/&quot;/g, `"`);
pageData = JSON.parse(pageData)

where pageData is an object (that may hold other objects)

Growyn
  • 31
  • 3