I have an array of json objects which I output using a Handlebars template; I am currently doing using {{#each object}}...{{/each}}. I now need to sort the objects by one of the object's properties, which again is no problem using a handlebars helper & coffeescript, however, I have a problem in my template in that I cannot work out how to iterate over the sorted array using each.
My research so far indicates that I probably need to write a custom Handlebars helper which will, in effect, be:
{{#each_with_sort array}}
My existing sort helper is like this
Handlebars.registerHelper sort_me =>
myArray.sort (a,b)->
return if +a.sort_index >= +b.sort_index then 1 else -1
but, I am struggling to be able to use the sorted array in the template - for example, it is not as simple as
{{#each sort_me(myArray)}}
The data is coming from a third party API, so I have to perform sorting in handlebars/coffeescript.
A Handlebars helper call is a simple identifier, followed by zero or more parameters (separated by a space). Each parameter is a Handlebars expression that is evaluated exactly the same way as described above in "Basic Usage": template {{firstname}} {{loud lastname}}
registerHelper("noop", function(options) { return options. fn(this); }); Handlebars always invokes helpers with the current context as this , so you can invoke the block with this to evaluate the block in the current context.
compile' and 'Handlebars. precompile' create a function. This function can be called as template(context, options) where context is the input object. options is an object that can have any of the following properties. data Pass in an object to define custom @variable private variables.
Handlebars expressions can be used to: Map Export and Import application fields.
The easiest thing to do would be to sort the data before it gets to Handlebars, then you can use {{#each ...}}
as usual and no helpers are needed. This sort of approach is quite common with Handlebars, the template is often split into two pieces: a (Java|Coffee)Script piece for data mangling/rearrangement and the template proper.
As an aside, you'll want to adjust your comparator function to behave property. From the fine manual:
If
compareFunction
is supplied, the array elements are sorted according to the return value of the compare function. Ifa
andb
are two elements being compared, then:
- If
compareFunction(a, b)
is less than 0, sorta
to a lower index thanb
, i.e. a comes first.- If
compareFunction(a, b)
returns 0, leavea
andb
unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAscript standard does not guarantee this behaviour, and thus not all browsers (e.g. Mozilla versions dating back to at least 2003) respect this.- If
compareFunction(a, b)
is greater than 0, sortb
to a lower index thana
.
So you want to return 0
if a.sort_index
and b.sort_index
are the same, something more like this:
myArray.sort (a,b)->
a = +a.sort_index
b = +b.sort_index
return 1 if a > b
return 0 if a == b
return -1 if a < b
If you must do the sorting inside the template then you'd need to add a custom each_with_sort
helper to do both the sorting and the iteration, something like this:
# If you're always sorting by sort_index then you don't need the key argument
# and you might want to put the '+'-casting back in.
Handlebars.registerHelper('each_with_sort', (array, key, opts) ->
data = Handlebars.createFrame(opts.data) if(opts.data)
array = array.sort (a, b) ->
a = a[key]
b = b[key]
return 1 if a > b
return 0 if a == b
return -1 if a < b
s = ''
for e, i in array
data.index = i if(data) # Support the usual @index.
s += opts.fn(e, data: data)
s
)
and your template would be like this:
{{#each_with_sort array "sort_index"}}
...
{{/each_with_sort}}
Demo: http://jsfiddle.net/ambiguous/zusq2tt4/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With