Last Updated: February 25, 2016
·
5.249K
· ram9cc

Chaining Sorting and Searching With Array Controllers

Hi,

The Ember.SortableMixin faculty is built into Array controller.

It gives us a way to use 2 properties to control the activity of the sorting engine on the 'content' property.

App.GoodiesController = Ember.ArrayController.extend
  sortProperties:["name"]
  sortAscending: true

At this point - the 'content' or 'model' property now is sorted according to the ArrayController
and if you are looping over #each without any argument you get the benefits right away.

But what if you need to use the sorted content as input into another mechanism - say search results?

Let's say that you have set up a search field named 'searchText' in the bakery template
and you are using the observer pattern to get access to the field and then filtering based
on the searchText.

The searchResults property is what we will be iterating over instead of 'model' or 'content'

  <script type="text/x-handlebars" id="bakery">
At {{#link-to 'goodies' name}}"{{name}}" {{/link-to}}
    <br/>
    {{input type='text' value=searchText}}
    <!-- outlet is where goodies will appear (render) -->
    {{outlet}}
  </script>

  <script type="text/x-handlebars" id="goodies">
    You see the following goodies:
    <ul>
    {{#each item in searchResults}}
      <li>{{item.name}}</li>
    {{/each}}
    </ul>
  </script>

You have set up your controller to need the bakery searchText and are observing changes
to it - as well as filtering results from 'content' into 'searchResults'

searchResults begins life as a computed property defaultingTo 'content'

App.GoodiesController = Ember.ArrayController.extend({
  sortProperties:["name"],
  sortAscending: true,

  needs: "bakery",

  searchResults: Ember.computed.defaultTo("content"),

  filterItem: function (model) {
    searchInput = this.get('controllers.bakery.searchText')
    regexp = new RegExp(searchInput, "i");
    if(!searchInput || (searchInput && (0 == searchInput.length))) {
      return true
    } else if (-1 != model.name.search(regexp)) {
      return true
    } else {
      return false
    }
  },

  searchFilter: function() {
    searchInput = this.get('controllers.bakery.searchText')
    Ember.Logger.debug("someone is looking for " + this.get("controllers.bakery.searchText"))
    this.set('searchResults',this.get('content').filter(this.filterItem.bind(this)))
  }.observes("controllers.bakery.searchText"),
})

This gives you the ability to filter by results ... but now the sorting is not working.

This is where the property 'arrangedContent' of Ember.SortableMixin comes in handy.

by changing two lines to use 'arrangedContent' instead of 'content' you end up with both searching and sorting

App.GoodiesController = Ember.ArrayController.extend({
  sortProperties:["name"],
  sortAscending: true,

  needs: "bakery",

  // search on the sorted 
  searchResults: Ember.computed.defaultTo("arrangedContent"),

  filterItem: function (model) {
    searchInput = this.get('controllers.bakery.searchText')
    regexp = new RegExp(searchInput, "i");
    if(!searchInput || (searchInput && (0 == searchInput.length))) {
      return true
    } else if (-1 != model.name.search(regexp)) {
      return true
    } else {
      return false
    }
  },

  searchFilter: function() {
    searchInput = this.get('controllers.bakery.searchText')
    Ember.Logger.debug("someone is looking for " + this.get("controllers.bakery.searchText"))

   // search on the sorted
    this.set('searchResults',this.get('arrangedContent').filter(this.filterItem.bind(this)))

  }.observes("controllers.bakery.searchText"),
})

There you have it - chaining sorting and searching together.

1 Response
Add your response

Perfect! I had no idea about this mystical arrangedContent property. Exactly what I needed, thanks a lot.

over 1 year ago ·