Last Updated: February 25, 2016
·
3.212K
· bashir

Sorted Collections - SortedArrayController in Ember.js

Problem

Need a collection of objects that always render in a sorted order and not the insert order. For example showing events ordered on timestamp.
Update: added maximum size so it will always trim the collection to a running set of n latest items.

Solution

I created this small extension to ember that will keep the collection always sorted (based on a sortFunction or default sort order). It also supports reverse order and random order. The code is in coffeescript but you can convert it to javascript via this tool.

Ember.SortedArrayController = Ember.ArrayController.extend(
  sortOrder: "normal"
  sortFunction: null
  inputCollectionName: "content"
  outputCollectionName: "content"
  maxCollectionSize: -1

  init: ->
    @set(@inputCollectionName, [])
    @addObserver(@inputCollectionName + '.@each', -> @elementAdded())
    @addObserver(@outputCollectionName + '.@each', -> @trimArray())

  elementAdded: (->
    context = @
    content = @get(@inputCollectionName)

    if @sortOrder == "normal"
      if @sortFunction? then content.sort((a,b)-> context.sortFunction(a,b)) else content.sort()
    else if @sortOrder == "reverse"
      if @sortFunction? then content.sort((a,b)-> context.sortFunction(b,a)) else content.reverse()
    else if @sortOrder == "random"
      content.sort((a,b)-> 0.5 - Math.random("deadbeef"))

    @set(@outputCollectionName, content)
  )

  trimArray: (->
    content = @get(@outputCollectionName)
    @set(@outputCollectionName, content.slice(0, @maxCollectionSize-1))if (@maxCollectionSize > 0) and (content.length > @maxCollectionSize)
  )
)

window.myArray = Ember.SortedArrayController.create()
myArray.content.pushObjects(["Jack", "Cassandra", "Raj"])

window.myArray2 = Ember.SortedArrayController.create({sortOrder: "reverse"})
myArray2.content.pushObjects(["Jack", "Cassandra", "Raj"])

window.myArray3 = Ember.SortedArrayController.create({sortOrder: "random"})
myArray3.content.pushObjects(["Jack", "Cassandra", "Raj"])

you will get the following results:

myArray.content
["Cassandra", "Jack", "Raj"]
myArray2.content
["Raj", "Cassandra", "Jack"]
myArray3.content
["Jack", "Raj", "Cassandra"]

1 Response
Add your response

I made a gist out of the js / non-coffeescript version: https://gist.github.com/chrisjlee/31d1ea4f7cd90517b2d8

over 1 year ago ·