Ember.computed.sort not invalidating cache


#1

I’m sorting an array of objects in my app and some of the parameters are sorted alphabetically, while others are sorted as integers:

_sortedContent: Ember.computed(
  '_alphaSortedContent',
  '_intSortedContent',
  '_sortKey',
  '_sortOrder',
  function () {
    console.log('_sortedContent');
    let columns = Ember.get(this, 'columns');
    let sortKey = Ember.get(this, '_sortKey');
    let selectedColumn = Ember.A(columns).findBy('propertyName', sortKey);

    if (typeof selectedColumn === 'undefined' || typeof sortKey === 'undefined') {
      return Ember.get(this, 'content');
    }

    switch (Ember.get(selectedColumn, 'sortType')) {
      case 'int':
        console.log('_intSortedContent');
        return Ember.get(this, '_intSortedContent');
      default:
        return Ember.get(this, '_alphaSortedContent');
    }
  }
),

_alphaSortedContent: Ember.computed.sort('content', '_sortDefinition'),

_intSortedContent: Ember.computed.sort('content',
  function (a, b) {
    let aSortKey = parseInt(Ember.get(a, Ember.get(this, '_sortKey')));
    let bSortKey = parseInt(Ember.get(b, Ember.get(this, '_sortKey')));
    let sortOrder = Ember.get(this, '_sortOrder');

    if (aSortKey > bSortKey) {
      console.log(`aSortKey:${aSortKey}, bSortKey:${bSortKey}, sortOrder:${sortOrder}`);
      console.log('greater than');
      return (sortOrder === 'asc') ? 1 : -1;
    } else if (aSortKey < bSortKey) {
      console.log(`aSortKey:${aSortKey}, bSortKey:${bSortKey}, sortOrder:${sortOrder}`);
      console.log('less than');
      return (sortOrder === 'asc') ? -1 : 1;
    }
    return 0;
  }
),

The _alphaSortedContent works fine and I can toggle between asc and desc (_sortDefinition is a computed property on _sortKey and _sortOrder so it changes when _sortOrder changes). But, the _intSortedContent won’t update when _sortOrder changes from asc to desc. _sortedContent is being fired and it calls _intSortedContent but it looks like _intSortedContent is then returning a cached copy rather than recalculating.

What’s the best way to invalidate the cache of intSortedContent?

Thanks!


#2

I’m having a hard time figuring out what the problem might be just looking at your example and reading your description. You shouldn’t have to manually invalidate your sort cache.

Can you make an ember-twiddle that demonstrates this issue? I’d be happy to help you solve it once I can see all the pieces working together.


#3

Sure. I can put together a twiddle. But, the main problem – I think – is that both “content” and the sort function don’t change. The sort function relies on the component’s state (i.e. sortOrder) so it will give different results depending on that. So, having an impure sort function seems to be the root of the problem.


#4

I’m sorry, that was my mistake. Yes, I think you’re right that there really isn’t a way to use a “sort function” with Ember.computed.sort that can allow for the order to be easily mutated.

You “could” use an observer and this.notifyPropertyChange('content'), that would almost certainly trigger a rebuild of that sort. But that’s pretty taboo and definitely adds boilerplate.

If it were me, I would take the _sortedContent computed approach. If I was doing this a lot, then I would try to build my own computed macro for my app.


#5

No worries. I did put the twiddle together here.

I did end up solving this by creating ascIntSortedContent and descIntSortedContent that are both pure functions. Doesn’t feel very DRY but what can you do ¯\(ツ)