Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handlebars.js - Each and getter

I'm using Handlebars.js and got stuck in a problem I can't solve.

I want to iterate through an array within a template, but the problem is that the expression I'm using for the iterator is a getter and not an array.

A piece of code that illustrates the problem is the following one:

HTML:

<script id="template" type="text/x-handlebars">
    Accessing directly: {{array}} <br/>
    Accessing by getter: {{getArray}} <br/>

    <br/>

    Looping directly:
    <ul>
    {{#each array}}
        <li>{{this}}</li>
    {{/each}}
    </ul>

    <br/>

    Looping by getter:
    <ul>
    {{#each getArray}}
        <li>{{this}}</li>
    {{/each}}
    </ul>
</script>

<p id="content"></p>

JS:

var template = Handlebars.compile($("#template").html());
var element = {
    array: [0, 1, 2],

    getArray: function() {
        return this.array;
    }
};

$("#content").html(template(element));

The problem is that the each that uses the getter does nothing. This can be seen in this jsFiddle.

Is there any clean way to perform this using the getter, or should I write a helper or something like an auxiliary function?

Thanks!

like image 432
eze.scaruli Avatar asked Jan 16 '23 03:01

eze.scaruli


2 Answers

{{#each}} expects an array and it won't understand anything else. You could add a simple custom helper for this, you'd just have to remember to use fn.call(this) if you expect this:

getArray: function() {
    return this.array;
}

to have the right this. Something like this would probably do the trick:

Handlebars.registerHelper('smart_each', function(a, block) {
    if(typeof a == 'function')
        a = a.call(this);
    var s = '';
    for(var i = 0; i < a.length; ++i)
        s += block(a[i]);
    return s;
});

Demo: http://jsfiddle.net/ambiguous/yuPfD/

You might want to look at the {{#each}} implementation in the Handlebars source to spruce that up a bit but I'll leave that as an exercise.

like image 90
mu is too short Avatar answered Jan 31 '23 00:01

mu is too short


If you use proper JavaScript getters, your technique will work. Here's an example using classes, available in ES6. For an ES5 example of the code below, see this version which uses babel.io's repl.

'use strict'

const handlebars = require('handlebars')
const template = "{{#each letters}} {{this}} {{/each}}"
var context

class Alphabet {
  get letters() {
    return 'abc'.split('')
  }
}

context = new Alphabet()
console.log('class instance with getter methods:')
console.log(handlebars.compile(template)(context))


context = {
  letters: 'xyz'.split('')
}

console.log('regular object:')
console.log(handlebars.compile(template)(context))

The output:

❯ node index.js
class instance with getter methods:
 a  b  c 
regular object:
 x  y  z 
like image 41
Zeke Avatar answered Jan 30 '23 23:01

Zeke