cat-t
cat-t

Reputation: 1376

Em.Computed.sort triggers computed property twice

One of the components in my app contains an array that is copied, filtered, sorted, sliced and then finally looped through. I'm having problems with the Em.computed.sort() part which seems to trigger another computed property to run twice (which then causes a bunch of other issues in my app).

{{#each item in final}}
    <li>{{item.name}} -- {{item.age}}</li>
{{/each}}

<button {{action "changeModel"}}>change model</button>

.

// initial property copied
initial: function(){
    return this.get('model').slice()
}.property('model'),

// sorted
sortProp: ['age:desc'],
sorted: Ember.computed.sort('initial', 'sortProp'),

// slice it and then loop through it - this function runs twice
final:  function(){
    return this.get('sorted').slice(0, 5)
}.property('sorted.[]'),

I have a simplified version of my issue - see my jsbin.

Basically, when the model changes, the final() function runs twice - once containing the old model data, and a second time with the new, updated model data. During both times the initial data is correct, but Em.computed.sort is only updated with the new, correct data the second time final() runs.

Is there a way to avoid final being called twice?

Upvotes: 1

Views: 838

Answers (2)

Andrew Hacking
Andrew Hacking

Reputation: 6366

Be aware that Embers array computed support is very fragile and has a number of issues.

My recommendation is don't use them as they are unlikely to be fixed any time soon as computed array properties are just too complex to get right with the current approach in Ember.

Instead just use a regular property depending on '[email protected]' that slices the model array and returns a new sorted array.

If you look at the underlying array computed sort implementation in Ember you will see that the simple approach I describe behaves correctly and works efficiently compared to the daunting amount of code and state tracking in Ember.

If you are concerned with sort efficiency then I recommend using a tsort implementation as it is often O(n) for interactive changes as it exploits runs and partially sorted arrays.

Upvotes: 1

Kalman
Kalman

Reputation: 8131

I believe the issue is that you are not just adding/removing values to the model array, but are replacing it altogether. Therefore, perhaps Ember.computed.sort is not working for you as you expect it to.

The following seems to work

  sorted: function(){
    return this.get('initial').sortBy('age').reverse();    
  }.property('initial'),


  // slice it and then loop through it
  final: function(){
    console.log('FINAL ran', this.get('initial.length'), this.get('sorted.length'));

    return this.get('sorted').slice(0, 5)
  }.property('sorted'),

See the working jsbin here

Upvotes: 2

Related Questions