Reputation: 1376
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
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
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