Handlebars.js: Feature request: built-in "join" helper

Created on 27 Oct 2011  路  8Comments  路  Source: handlebars-lang/handlebars.js

I couldn't figure out a way to use a built-in helper to join a list of items with a delimiter. If there is already a built-in helper or combination of built-in helpers that can do this, please let me know. Otherwise, I suggest that you add a built-in helper called "join" that has a parameter for the delimiter.

For example, the template would contain something like this:

 {{join myArray delimiter=", "}}

I ended up registering my own helper for my immediate needs:

Handlebars.registerHelper("join", function(context, block) {
     return context.join(block.hash.delimiter);
});

This should be modified to handle cases when context is null, the context is not an array, the delimiter is null, etc.

feature

Most helpful comment

For node:

Handlebars.registerHelper( "join", function( array, sep, options ) {
    return array.map(function( item ) {
        return options.fn( item );
    }).join( sep );
});
<p>
    {{#join companies "<br>"}}
        {{name}}
    {{/join}}
</p>

All 8 comments

I just did this for myself today:

Handlebars.registerHelper('join', function(val, delimiter, start, end) { 
    return [].concat(val).slice(start, end).join(delimiter); 
});

If val is not an array it has the effect of just returning val. The 2nd-4th parameters are entirely optional (default delimiter is ","). I've only tested on Chrome so far.

Update: this breaks in IE8. [...].slice(undefined, undefined) returns an empty array rather than the entire array as in other browsers. Also, if you don't supply a delimiter in your template definition, Handlebars passes the hash object as the delimiter, which IE renders as '[Object]' rather than a comma as other browsers. My revised version looks like this:

Handlebars.registerHelper('join', function(val, delimiter, start, end) {
    var arry = [].concat(val);
    delimiter = ( typeof delimiter == "string" ? delimiter : ',' );
    start = start || 0;
    end = ( end === undefined ? arry.length : end );
    return arry.slice(start, end).join(delimiter); 
});

Not as tersely elegant, but sanity-checking your inputs is probably a good practice.

--Chad

I have incorporated ceberle's suggestions:

//Handlebars "join" block helper that supports arrays of objects or strings.  
//If "delimiter" is not speficified, then it defaults to ",".  You can use "start", 
//and "end" to do a "slice" of the array.

Handlebars.registerHelper('join', function(items, block) {
    var delimiter = block.hash.delimiter || ",", 
        start = start = block.hash.start || 0, 
        len = items ? items.length : 0,
        end = block.hash.end || len,
        out = "";

        if(end > len) end = len;

    if ('function' === typeof block) {
        for (i = start; i < end; i++) {
            if (i > start) out += delimiter;
            out += block(items[i]);
            if('string' === typeof items[i])
                out += items[i];
            else
                out += block(items[i]);
        }
        return out;
    } else { 
        return [].concat(items).slice(start, end).join(delimiter);
    }
});

Oops, I meant to take out one line:

//Handlebars "join" block helper that supports arrays of objects or strings.  
//If "delimiter" is not speficified, then it defaults to ",".  You can use "start", 
//and "end" to do a "slice" of the array.

Handlebars.registerHelper('join', function(items, block) {
    var delimiter = block.hash.delimiter || ",", 
        start = start = block.hash.start || 0, 
        len = items ? items.length : 0,
        end = block.hash.end || len,
        out = "";

        if(end > len) end = len;

    if ('function' === typeof block) {
        for (i = start; i < end; i++) {
            if (i > start) 
                out += delimiter;
            if('string' === typeof items[i])
                out += items[i];
            else
                out += block(items[i]);
        }
        return out;
    } else { 
        return [].concat(items).slice(start, end).join(delimiter);
    }
});

@jlubean: what version of handlebars are you using? I am unable to get it to work with up to beta 4. I get the following error when using syntax like:

{{join list_of_words delimiter=","}}

The error:

Uncaught Error: Parse error on line 35:
..._of_words delimiter=&quot;,&quot;}}</tex
-----------------------^
Expecting 'STRING', 'INTEGER', 'BOOLEAN', 'ID'

I was using beta 3. Take a look at my working example at http://jsfiddle.net/jlubean/YS3EV/

I wrote this: http://mametipsum.herokuapp.com/. I'd rather not require that people have to specify a helper like this (see the "Template" tab). I'd like to keep it simple. I'd like spaces to be the default when printing an array. I'm happy to override the default array helper, but how do I do that? Thanks.

Personally, I think Handlebars is best kept simple. If someone would like to put together a repo/gist with useful helpers then we could probably link to it or otherwise highlight it.

For node:

Handlebars.registerHelper( "join", function( array, sep, options ) {
    return array.map(function( item ) {
        return options.fn( item );
    }).join( sep );
});
<p>
    {{#join companies "<br>"}}
        {{name}}
    {{/join}}
</p>
Was this page helpful?
0 / 5 - 0 ratings