Why does trimmed string in handlebars template not render?

Viewed 193

Can anyone explain why in the following example result prints as [object Object] to the console when typeof result returns string?

I took this example from the very bottom of the handlebars documentation here: https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access

I assume that this may have something to do with the fact that handlebars does not allow access to the toString method of the aString prototype but if the documentation is correct this should work.

var template = Handlebars.compile(document.getElementById('template').innerHTML);

var result = template({ aString: "  abc  " }, {
    allowedProtoMethods: {
      trim: true
    }
  });

console.log(result, typeof result);

document.getElementById('output').innerHTML = result;
<script src="https://unpkg.com/handlebars@latest/dist/handlebars.js"></script>

<div id="output"></div>
<script type="template/handlebars" id="template">{{aString.trim}}</script>

1 Answers

This is essentially a typical "losing this" problem. When handlebars evaluates aString.trim, it gets back a reference to String.prototype.trim. At this point the "connection" to aString is lost and trim doesn't know on which value to operate on.

This can be demonstrated by replicating this with a custom object + methods:

var template = Handlebars.compile(document.getElementById('template').innerHTML);

var result = template({
  foo: { 
    data: "data",
    getData() { return this.data || 'not found'},
    staticData() { return 'static data'; }
  },
});

document.getElementById('output').innerHTML = result;
<script src="https://unpkg.com/handlebars@latest/dist/handlebars.js"></script>

<div id="output"></div>
<script type="template/handlebars" id="template">{{foo.getData}} {{foo.staticData}}</script>

See how it renders not found instead of data? That's because this refer to the object in foo, it refers to something else (possibly the global object).

In other words it looks like you cannot call methods that depend on this that way.

You could use a helper instead.

Related