Sean
Sean

Reputation: 1888

Ember.js add class to action helper template

How can I specify a class to an item when clicked with Ember. I am using a Handlebars action on the elements of a table to sort by properties. I want to add a class to the property being sorted so I can show the user the current property being sorted. How can I do this?

I have an ember controller shown below:

App.UsersController = Ember.ArrayController.extend
  title: 'Users'
  count: Ember.computed.alias 'length'
  sortProperties: ['username']
  actions:
    sort: (property) ->
      console.log property
      if @get('sortProperties')[0] is property
        @set('sortAscending', !@get 'sortAscending')
      else
        @set 'sortProperties', [property]
        @set('sortAscending', true)

The controller allows me to click on headings in a table to sort the table. The html is shown below:

<thead>
  <tr>
    <th>Action</th>
    <th class="sort" {{action sort 'last'}}>Last</th>
    <th class="sort" {{action sort 'first'}}>First</th>
    <th class="sort" {{action sort 'username'}}>Username</th>
    <th class="sort" {{action sort 'email'}}>Email</th>
  </tr>
</thead>

Upvotes: 2

Views: 480

Answers (2)

lcoq
lcoq

Reputation: 10726

Create a currentSort property (optional)

First, I created a currentSort property on your App.UsersController which cleans a little bit the code. We'll use it later.

App.UsersController = Ember.ArrayController.extend
  sortProperties: ['username']
  currentSortBinding: 'sortProperties.firstObject'

  actions:
    sort: (sort) ->
      if sort is @get('currentSort')
        @toggleProperty 'sortAscending'
      else
        @setProperties
          currentSort: sort
          sortAscending: true

Define a custom view for each <th>

You'll then have to define a custom view for the <th> which will do 2 things:

  • Have a class active-sort when the sort of the view is the current
  • Change the controllers current sort when clicking the view

It will looks like this:

App.SortView = Ember.View.extend
  template: Ember.Handlebars.compile('{{view.sortName}}')
  tagName: 'th'
  sortName: null # (will be different for each <th> : `last`, `first`,..)

  classNameBindings: [ ':sort', 'isCurrent:active-sort' ]

  isCurrent: (->
    @get('sortName') is @get('controller.currentSort')
  ).property('sortName', 'controller.currentSort')

  click: ->
    var newSort = @get('sortName');
    @get('controller').send('sort', newSort);

Here we customized the view class names, and we handled click event on the view.

Insert a custom view for each sort

This is really simple to insert views in templates:

<thead>
  <tr>
    {{view App.SortView sortName="default"}}
    {{view App.SortView sortName="price"}}
    {{view App.SortView sortName="alphabetical"}}
  </tr>
</thead>

You can test all of this in a working JSBin

Upvotes: 2

Pascal Boutin
Pascal Boutin

Reputation: 1264

I don't know if this is the best workaround, but you could have some "sort flag" that you could bind CSS on.

In your controller (in "classic" javascript) :

sortedByLast : function() { return this.get("sortProperties")[0] === "last" }.property("sortProperties.@each")
// etc ...

In your template :

<th {{bind-attr class=":sort sortedByLast:current-sort"}} {{action sort 'last'}}>Last</th>

So the sort class would always be on, and the current-sort would only be there if it match its proper flag.

Upvotes: 0

Related Questions