Search code examples
ember.jsember-dataember-cli

Ember Computed Property on hasMany relationship not updating and doubles on save


I have two models, one with hasMany relationship to the other:

Shipment:

import DS from 'ember-data';

export default DS.Model.extend({
  pickup_address: DS.belongsTo('address', { inverse: null }),
  delivery_address: DS.belongsTo('address', { inverse: null }),
  shipment_lines: DS.hasMany('shipment-line', { inverse: null }),
  shipmentPrice: Ember.computed('shipment_lines.@each.package_price', function () {
    let price = 0;
    this.get('shipment_lines').forEach(function(shipment_line) {
      price += Number(shipment_line.get('package_price'));
    });
    return price;
  }),
});

And the shipment line model:

import DS from 'ember-data';

export default DS.Model.extend({
    description: DS.attr('string'),
    package_weight: DS.attr('number'),
    package_length: DS.attr('number'),
    package_width: DS.attr('number'),
    package_height: DS.attr('number'),
    package_price: DS.attr('number'),
});

In the controller, when I add new shipment lines to a shipment, I fetch the price for the package from the API and add it to the shipment line:

addShipmentLine(shipmentLine) {
  // Get price for shipment line
  this.getShipmentLinePrice(shipmentLine);

  // Add shipment line to shipment
  let shipment = this.get('shipment');
  shipment.get('shipment_lines').addObject(shipmentLine);
},

The getShipmentLinePrice function (simplified):

getShipmentLinePrice(shipmentLine) {
    ...
    // Get weight and type
    let weight = shipmentLine.get('package_weight');
    let length = shipmentLine.get('package_length');
    let height = shipmentLine.get('package_height');
    let width  = shipmentLine.get('package_width');

    // Fetch price from API
    this.get('price').getPackagePrice(weight, length, height, width).then(
        (price) => {
            shipmentLine.set('package_price', price['price']);
        }
    );
}

And lastly, when I try to print the shipmentPrice in the template, it does not update. Even though the price is returned from the server and shipment_lines package_price is set.

Also, when I save the shipment with shipment.save(); and the route is redirected to the show-page, the price is doubled until I refresh the page. After a page refresh, everything displays correctly.

So the first question is, how can I get the shipment computed property shipmentPrice to update when adding new shipment line objects? Or is it not possible?

The second question is, why is the price doubled after a save?


Solution

  • I finally figured this one out. Well, at least I found a way around it. After saving the model, I manually reset the shipmentPrice to 0:

    freight_order.save().then(
        (new_freight_order) => {
            shipment.set('shipmentPrice', 0);
            this.transitionToRoute('shipments.show', new_freight_order.id);
        }
    );
    

    I guess the server respons got added to the computed value for some reason.