Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ember.js sorting and filtering children of a hasMany relationship in parent route

Update #2

I found that when I refactored the filtering logic to take place in a compound computed property within the PostController instead of within individual routes, I was able to get it working. The solution was ultimately dependent upon a single dynamic variable set by the specific #linkTo route action that triggered filtering changes within a PostController computed property. I have a lot of work to catch up on so I can't post the solution to this specific question now, but when I can I will detail an explanation of the solution below. For now I have marked @twinturbo's answer as correct for the partial but incredibly helpful guidance he gave below. Thanks again man!! Much appreciated!!

Update #1

The latest fiddle is at http://jsfiddle.net/aZNRu/14/ with @twinturbo's help, sorting the "rank" attribute of Comments in its Post parent controller is working, along with basic filtering. Still having the problem of not getting auto updating views when in a filtered route and a new comment is created.

Original Question

I see that there is talk of combining the sortable mixin with filtering functionality, but for now, as you can see in my jsfiddle example, I'm having issues with both sorting and filtering:

1) I can't figure out how to sort by a specific child attribute in the controller of its parent. If we have:

App.Post = DS.Model.extend({
    title: DS.attr('string'),
    post: DS.attr('string'),
    comments: DS.hasMany('App.Comment')
});

App.Comment = DS.Model.extend({
    post: DS.belongsTo('App.Post'),
    description: DS.attr('string'),
    isActive: DS.attr('boolean'),
    rank: DS.attr('number')
});

App.Router.map(function() {
  this.resource("posts", { path: "/" }, function() {
    this.resource('post', { path: ':post_id' }, function() {
        this.route('active');
        this.route('inactive');
     });
   });
});

I want to be able to sort each post's comments in ascending order by it's "rank" attribute. I want to do something like:

App.PostController = Ember.ObjectController.extend({
    sortProperties: ['comments.rank']

but for one, I think sortProperties only works on arrayControllers, and I don't think it can work more than one level deep. How could I achieve this?

2) The second problem is not getting auto-updating views when in a filtered route. For example, if you view the jsfiddle and go into the active filtered route by clicking "Active Comments" you get a nice filtering effect on the current data. But if you remain in the active route and create a new record that is active by clicking "Add New Comment," the record does not automatically render under "Active," and only appears if you click on another route and then return to it.

Am I setting up the route filtering incorrectly in the route or referencing it wrong in the template?

App.PostActiveRoute = Ember.Route.extend({
  setupController: function() {
    var post = this.controllerFor('post').get('model'),
    comments = post.get('comments');

    var activeComments = comments.filter(function(comment) {
      if (comment.get('isActive')) { return true; }
    });

    this.controllerFor('post').set('filteredComments', activeComments);
  }
});


<ul>
    {{#each comment in filteredComments}}
        <li>{{comment.rank}} {{comment.description}} - isActive: {{comment.isActive}}</li>
    {{/each}}
</ul>

Any insight you could give on these issues would be greatly appreciated!

like image 321
Bryan Langslet Avatar asked Jan 30 '13 09:01

Bryan Langslet


2 Answers

but for one, I think sortProperties only works on arrayControllers, and I don't think it can work more than one level deep. How could I achieve this?

You are correct that sortProperties only works on Ember.ArrayController.

You really don't need to do anything fancy to achieve this. Simply wrap the comments array in a new ArrayProxy that includes the sortable mixin. Then you can sort the comments. Then you don't need a nest property because you're sorting an array of comments.

Please don't extend DS.ManyArray. There is no need for that.

As for sorting and filtering, you need to use composition here. That means creating something like filteredContent and sortedContent. Then you can have sortedContent use filteredContent.

Update:

PostController = Ember.ObjectController.extend({
  comments: (function() {
    return Ember.ArrayProxy.createWithMixins(Ember.SortableMixin, {
      sortProperties: ['rank'],
      content: this.get('content.comments')
    });
  }).property('content.comments')
like image 58
ahawkins Avatar answered Nov 06 '22 00:11

ahawkins


This can be done with a computed property macro, too.

PostController = Ember.ObjectController.extend({
 commentSortProperties: ['rank:desc', 'createdAt:asc'],
 comments: Em.computed.sort('model.comments', 'commentSortProperties')
});

Take a look at the code here.

like image 20
swastik Avatar answered Nov 05 '22 22:11

swastik