Last Updated: February 25, 2016
·
3.55K
· 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 ·

Have a fresh tip? Share with Coderwall community!

Post
Post a tip
Did you know?

JavaScript on a page runs with the privileges of that origin. One altered library, tag manager, or snippet can read inputs, change what people see, and call your APIs as the user.

Security insights from Cside