Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handlebars.js custom function sort

Tags:

javascript

I am using Handlebars to display comments.

{{#each COMMENTS}}
     <div class="heightfix">
          <div class="commentIcon"></div>&nbsp;&nbsp;
             <label id="commentDate1" class="bold">{{COMMENTON}}</label>:&nbsp;
             <label id="commentCreator1" class="bold">{{COMMENTBY_FIRSTNAME}} {{COMMENTBY_LASTNAME}}</label>&nbsp;&nbsp;
             <label class="commentContent" id="commenttext_{{ID}}">{{COMMENTTEXT}}</label>
     </div>                                  
{{/each}}   

In those COMMENTS, I have INDEX. I would like to display the comments as per their index. Comment 0 Comment 1 Comment 2 Comment 3 .....

How do I achieve this using custom functions ? Thanks

like image 361
user533844 Avatar asked Apr 12 '26 05:04

user533844


1 Answers

Method 1: Custom Accessor

If you have control over the context (and you probably do), you can implement this with property accessors. Let's say your context contains the comments in jumbled order:

var context = {
    comments: [
        { idx:6, text:'violet' },
        { idx:1, text:'orange' },
        { idx:0, text:'red' },
        { idx:5, text:'indigo' },
        { idx:3, text:'green' },
        { idx:2, text:'yellow' },
        { idx:4, text:'blue' },
    ],
};

You could just sort the comments array in place before rendering your template (note that for numeric values, you can just subtract them to get natural ordering):

context.comments.sort( function(a,b) { return a.idx - b.idx; } );

The problem with that is that will modify the context object, which you may not want to do. A solution is to provide a custom accessor that will return the comments sorted by some custom property. Here's how we can do that:

Object.defineProperty( context, 'commentsByIdx', {
    get: function() {
        // note that we call concat() to create a copy of
        // the array; otherwise we are modifying the
        // the original array, which is a side effect
        return this.comments.concat()
            .sort( function(a,b) { return a.idx - b.idx } );
    }
});

You can see this solution in action here: http://jsfiddle.net/Jammerwoch/ShZLY/

Method 2: Handlebars Block Helper

The other approach is to implement a Handlebars block helper. This approach will work better if you don't have much control over the context (or don't want to contaminate it with custom properties). Simply register a Handlebars helper:

Handlebars.registerHelper('eachByIdx', function(context,options){
    var output = '';
    var contextSorted = context.concat()
        .sort( function(a,b) { return a.idx - b.idx } );
    for(var i=0, j=contextSorted.length; i<j; i++) {
        output += options.fn(contextSorted[i]);
    }
    return output;
});

And call it like so in your template:

{{#eachByIdx comments}}
    <li>{{text}}</li>
{{/eachByIdx}}

See it in action here: http://jsfiddle.net/Jammerwoch/aeCYg/1/

All in all, I find the first method preferable, as it creates a new view of your data that's potentially useful outside of Handlebars. Furthermore, to the casual reader of Handlebars code, it will make more sense.

like image 145
Ethan Brown Avatar answered Apr 17 '26 15:04

Ethan Brown



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!