Robert LeBlanc
Robert LeBlanc

Reputation: 60

ember.js component sort model based on if property is set

I'm new to Ember and am using Ember.js 2.10. I'm trying to only use components instead of controllers. I'm trying to create a component that creates a list that is a list of links or just items and is sorted or not sorted based on the properties sent in. I have the link part working, but I can't seem to get the sort working without repeating a lot of code which makes me think I'm doing something wrong. I tried moving the sort logic into a computed property, but it doesn't work. If I don't specify a sortBy property, it still sorts the list. If I do specify as sortBy property, I don't get a list at all and the console.log shows what is returned as ComputedProperty.

This seems basic enough that I shouldn't have to do this, so if there is an Ember way of doing this, I'd like to know. Regardless, I'd like to understand what I'm doing wrong for the academic value of it.

app/components/column-list.js

import Ember from 'ember';

export default Ember.Component.extend({
  tagName: 'ul',
  classNames: ['column-list'],
  sortedItems: Ember.computed('items', 'sortBy', function() {
    if (this.get('sortBy') !== undefined) {
      let sd = [ this.get('sortBy') ];
      return Ember.computed.sort(this.get('items'), sd);
    } else {
      return this.get('items');
    }
  }),
});

app/templates/components/column-list.hbs

{{#if sortBy}}
  {{#each sortedItems as |item|}}
    <li>
       {{#if link}}
         {{#link-to link item.id}}
           {{yield item}}
         {{/link-to}}
       {{else}}
         {{yield item}}
       {{/if}}
    </li>
  {{/each}}
{{else}}
  {{#each items as |item|}}
    <li>
       {{#if link}}
         {{#link-to link item.id}}
           {{yield item}}
         {{/link-to}}
       {{else}}
         {{yield item}}
       {{/if}}
    </li>
  {{/each}}
{{/if}}

app/templates/category/index.hbs

{{#column-list class="categories" sortBy="title" link="category.show" items=model as |i|}}
  {{i.title}}
{{/column-list}}

mirage/fixtures/category.js

export default [
  {
    id: 'main-dishes',
    title: 'Main Dishes',
  }, {
    id: 'cakes-pies-and-sweets',
    title: 'Cakes, Pies & Sweets',
  }, {
    id: 'langappie',
    title: 'Langappie',
  }, {
    id: 'dips-and-sauces',
    title: 'Dips & Sauces',
  }, {
    id: 'meat-dishes',
    title: 'Meat Dishes',
  }, {
    id: 'vegetable',
    title: 'Vegetable',
  }, {
    id: 'seafood-dishes',
    title: 'Seafood Dishes',
  }, {
    id: 'bread-and-cereals',
    title: 'Bread & Cereals',
  }
];

Update:

I twiddled the twiddle that @Jovica made and I'm getting "Assertion Failed: The sort definition for 'sortedItems' on must be a function or an array of strings", so I think I still have something wrong. Link to twiddle

Update2:

I found that I had a typo in my twiddle and got it working properly. The new twiddle has the right fix. Now to figure out why ember-mirage is ordering the data without me asking, but that is a different problem.

Upvotes: 0

Views: 527

Answers (2)

locks
locks

Reputation: 6577

Returning the Ember.computed.sort macro isn't doing what you think it is. You would have to use the sort methods on the Array class. The dependent keys are also not properly declared, it would be items.[] if the list is to be updated.

Here's a suggested solution that updates the sorting whenever the sort key that's passed into the component changes:

export default Ember.Component.extend({
  appName: 'Ember Twiddle',
  dishes: foo,
  sortedItems: Ember.computed.sort('dishes', 'sortBy')

  didReceiveAttrs() {
    if (this.get('sortBy')) {
      this.set('sortBy', [ this.get('sortBy') ]);
    else {
      this.set('sortBy', []);
    }
  }
});

And here's the template you need, because when sortBy is an empty array, the computed macro will not sort the array:

{{#each sortedItems as |item|}}
  <li>
    {{#if link}}
      {{#link-to link item.id}}
        {{yield item}}
      {{/link-to}}
    {{else}}
      {{yield item}}
    {{/if}}
  </li>
{{/each}}

Upvotes: 1

Jovica Šuša
Jovica Šuša

Reputation: 622

Try this

sortedItems: Ember.computed('items', 'sortBy', function() {
  if (this.get('sortBy') !== undefined) {
    let sd = this.get('sortBy');
    return this.get('items').sortBy(sd);
  } else {
    return this.get('items');
  }
}),

or shorter version

sortedItems: Ember.computed('items', 'sortBy', function() {
  let sortTerm = this.get('sortBy'),
      items    = this.get('items');
  return Ember.isBlank(sortTerm) ? items : items.sortBy(sortTerm);
}

Upvotes: 0

Related Questions