Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ember js @each one level deep but I have a two deep level relationship [duplicate]

I have to access a property that is two level's deep on my controller, but the [] only can access one level deep via the emberjs guide.

model(params) {
    params.paramMapping = {
        page: "page",
        perPage: "per_page",
        total_pages: "pages"
    };

    return this.findPaged('contractf', params);
},

setupController(controller, model) {
    model.forEach(function(item) {
        item.set('sale_price', item.get('dealers_sched_id.sale_price'));
    });

    controller.set('content', model);
},

Above, I have my model which is basically fetching all records in a pagination format in the contractf model. Then I set up my controller and loop through all those models and bind a sale_price property that goes into it's relationship to get the sale_price in the correct model relation.

Now in my template, I have this:

new_suggested_price: Ember.computed('selectedItems', 'selectedItems.[].sale_price', function() {
    var ret = 0;

    this.get('selectedItems').filterBy('car_used', 'N').forEach(function(contract){
        var salePrice = contract.get('sale_price');

        if (salePrice) {
            ret += (salePrice*100);
        }
    });

    return ret/100; // We *100/100, so we avoid a floating point calc error.
}),

Basically just gives me a number that is easily format-able. As you can see it depends on the selectedItems (which is basically the model, but filters by a property). So I have to go into each model item and find that sale_price I property I set and if it changes, this computed property will update. Reading Ember's guide, I couldn't do selectedItems.[].dealers_sched_id.sale_price because it only goes one level deep.

I thought setting a property on setupController would fix that issue, but it doesn't seem to because I'm still getting NaN as the sale_price value.

Now if I set a setTimeout function for 500 ms, it populates fine.. How do I get it defined on page load?

Thank you for any help.

like image 279
Haley Schillig Avatar asked Mar 15 '16 12:03

Haley Schillig


1 Answers

Why does this problem exist

Ember API indeed allows you to use only one level of @each/[] in your computed property dependencies.

This limitation is likely artificial as using two or more @each levels is a huge performance impact on internal observer maintenance.

Thus, you have to avoid more than one @each/[] in your CP dependency chains.

If you can't have a cake with N candles, have N cakes with one candle each

But sometimes your business dictates you to have to or more levels.

Fear not! This can be achieved with a chain of computed properties, where each property has only one @each level.

Say, you have Foo, Bar and Baz models and want to depend on

[email protected][email protected][email protected]

Here's a chain of computed properties you need to create:

  • barsArrays: computed('[email protected]') -- map foos by bars. You'll have an array of arrays of bars.
  • bars: computed('barsArrays.[]') -- flatten it to receive an array of bars.
  • bazesArrays: computed('[email protected]') -- map bars by bazes.
  • bazes: computed('bazesArrays.[]') -- flatten bazesArrays.
  • bazesNames: computed('[email protected]') -- map bazes by name.

How to make the chain shorter

Note that you can make this chain shorter (but not necessarily more performant) by relying on the fact that bar.bazes is a relationship array that is never replaced with a different array (only its content changes, but the array object stays the same).

  • bazesArrays: computed('[email protected]')-- map foos by bars, flatten, then map by bazes. You'll have an array of arrays of bazes.
  • bazes: computed('bazesArrays.[]') -- flatten bazesArrays.
  • bazesNames: computed('[email protected]') -- map bazes by name.

Here's a working demo: http://emberjs.jsbin.com/velayu/4/edit?html,js,output

like image 95
Andrey Mikhaylov - lolmaus Avatar answered Sep 18 '22 05:09

Andrey Mikhaylov - lolmaus