Sorting in Ember
Problem You have a collection of Post model object displayed in a template and you want to be able to sort ascending or descending on one or more keys. Solution Create (or if you already have one: update) a PostsController that contains an action that do the actual sorting. This action called is when you click on an element in the template. For this element you create an Ember component that imlements a click event handler and delegates the event to the controller. The main reason for creating a component for the sort element is that you want to update the state of the element with an appropriate icon (or color or whatever) indicating which key is used for sorting and if sorting happened in an ascending or descending order. By passing the controller's sortProperties and sortAscending properties we're able to remember the state and update and look of the element accordingly.
by bazzel
HTML
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/foundation/5.1.1/css/foundation.css">
<script src="http://builds.handlebarsjs.com.s3.amazonaws.com/handlebars-v1.3.0.js"></script>
<script src="http://builds.emberjs.com/tags/v1.5.0-beta.1/ember.js"></script>
<script src="http://builds.emberjs.com/tags/v1.0.0-beta.6/ember-data.js"></script>
<script type="text/x-handlebars">
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="posts">
<dl class="sub-nav">
<dt>Sort:</dt>
{{sorting-key title='Id'
key='id'
sortProperties=sortProperties
sortAscending=sortAscending
action='sort'}}
{{sorting-key title='Title'
key='title'
sortProperties=sortProperties
sortAscending=sortAscending
action='sort'}}
{{sorting-key title='Published'
key='published'
sortProperties=sortProperties
sortAscending=sortAscending
action='sort'}}
</dl>
<ul>
{{#each}}
<li>{{title}} ({{id}})
{{#if published}}<span>X</span>{{/if}}
</li>
{{/each}}
</ul>
</script>
<script type="text/x-handlebars" id="components/sorting-key">
<a {{action 'sort' 'title'}}>{{title}}</a>
</script>
SCSS
.sub-nav dd {
a:after {
content: " \25B4\25BE";
}
&.asc a:after {
content: " \25B4";
}
&.desc a:after {
content: " \25BE";
}
}
CoffeeScript
App = Ember.Application.create()
App.Store = DS.Store.extend()
App.ApplicationAdapter = DS.FixtureAdapter.extend()
App.Post = DS.Model.extend
title: DS.attr 'string'
published: DS.attr 'boolean'
App.Post.FIXTURES = [
id: 1
title: 'Perfect, just perfect'
published: yes
,
id: 2
title: 'It\'s about the future, isn\'t it?'
published: no
,
id: 3
title: 'Now that\'s a risk you\'ll have to take you\'re life depends on it'
published: yes
,
id: 4
title: 'Save the clock tower'
published: no
,
id: 5
title: 'Calvin, why do you keep calling me Calvin?'
published: yes
]
App.Router.map ->
@resource 'posts',
path: '/'
App.PostsRoute = Ember.Route.extend
model: ->
@store.find 'post'
App.PostsController = Ember.ArrayController.extend
actions:
sort: (property) ->
if @get('isSorted') and (@get('sortProperties')[0] is property)
@toggleProperty('sortAscending')
else
@set('sortProperties', [property])
@set('sortAscending', yes)
# Returning false prevents the action from bubbling
return false
App.SortingKeyComponent = Ember.Component.extend
tagName: 'dd'
classNameBindings: ['isSorted:active', 'isAsc:asc', 'isDesc:desc']
isSorted: (->
@get('sortProperties')?[0] is @get('key')
).property('sortProperties')
isAsc: (->
@get('isSorted') and @get('sortAscending')
).property('isSorted', 'sortAscending')
isDesc: (->
@get('isSorted') and not @get('sortAscending')
).property('isSorted', 'sortAscending')
click: ->
@sendAction 'action', @get('key')