EMBER WORKSHOP: Controllers, sorting

Ember.js Controllers, sorting

by jdcravens

HTML

<script src="http://builds.emberjs.com/handlebars-1.0.0.js"></script>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0-rc1/css/bootstrap.min.css">
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/foundation/5.1.1/css/foundation.css">
<script src="http://builds.emberjs.com/release/ember.js"></script>
<script src="http://builds.emberjs.com/tags/v1.0.0-beta.12/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";
  }
}

JavaScript

var App;

App = Ember.Application.create();

App.ApplicationStore = 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: true
  }, {
    id: 2,
    title: 'It\'s about the future, isn\'t it?',
    published: false
  }, {
    id: 3,
    title: 'Now that\'s a risk you\'ll have to take you\'re life depends on it',
    published: true
  }, {
    id: 4,
    title: 'Save the clock tower',
    published: false
  }, {
    id: 5,
    title: 'Calvin, why do you keep calling me Calvin?',
    published: true
  }
];

App.Router.map(function() {
  return this.resource('posts', {
    path: '/'
  });
});

App.PostsRoute = Ember.Route.extend({
  model: function() {
    return this.store.find('post');
  }
});

App.PostsController = Ember.ArrayController.extend({
  actions: {
    sort: function(property) {
      if (this.get('isSorted') && (this.get('sortProperties')[0] === property)) {
        this.toggleProperty('sortAscending');
      } else {
        this.set('sortProperties', [property]);
        this.set('sortAscending', true);
      }
      return false;
    }
  }
});

App.SortingKeyComponent = Ember.Component.extend({
  tagName: 'dd',
  classNameBindings: ['isSorted:active', 'isAsc:asc', 'isDesc:desc'],
  isSorted: (function() {
    var _ref;
    return ((_ref = this.get('sortProperties')) != null ? _ref[0] : void 0) === this.get('key');
  }).property('sortProperties'),
  isAsc: (function() {
    return this.get('isSorted') && this.get('sortAscending');
  }).property('isSorted', 'sortAscending'),
  isDesc: (function() {
    return this.get('isSorted') && !this.get('sortAscending');
  }).property('isSorted', 'sortAscending'),
  click: function() {
    return this.sendAction('action', this.get('key'));
  }
});