pusle
pusle

Reputation: 1523

Ember Data and each loop and nested objects in Handlebars

I have an issue when trying to display a list of objects where each object has nested objects and there is even another level of objects in those objects. The API-respons gives me this (simplified) JSON-data where there are many freight orders:

{
    "freightOrders": [{
        "id": 1,
        "comment": "Freight order comment",
        "shipments": [{
            "id": 1,
            "shipment_lines": [{
                "id": 1,
                "description": "A description",
                "package_weight": 900,
                "package_length": 1200,
                "package_height": 400,
                "package_width": 800
            }],
            "pickup_address": {
                "id": 1,
                "address": "The pickup address",
                "zip": "9000"
            },
            "delivery_address": {
                "id": 2,
                "address": "The delivery address",
                "zip": "8000"
            },
        }],
    }]
}

What I want is to display a list of all freight orders, and for the time being, access directly the first shipments-line for each order. In Handlebars I have tried

{{#each model as |order|}}
    <span>
        {{order.shipments.0.pickup_address.address}},
        {{order.shipments.0.pickup_address.zip}}
    </span>
{{/each}}

and

{{#each model as |order|}}
    {{#each order.shipments as |shipment|}}
        <span>
            {{shipment.pickup_address.address}},
            {{shipment.pickup_address.zip}}
        </span>
    {{/each}}
{{/each}}

Edit: Here is the order model as requested:

import DS from 'ember-data';

export default DS.Model.extend({
    comment: DS.attr('string'),
    shipments: DS.hasMany('shipment', { inverse: null })
});

and the shipment model for good measure:

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 })
});

Whatever I try to do, I am not able to access shipments element or any nested objects of the order object.

I can mention that I have also tried to create the shipments part as a component and pass order.shipments to the component, but to no prevail.

Searching SO and google does not reveal any hints only some examples of how to do nested each in ember 1.x

So, how can one access nested objects in an each-loop in Handlebars and Ember Data?

Upvotes: 1

Views: 640

Answers (1)

Jacob van Lingen
Jacob van Lingen

Reputation: 9567

I don't know if I got enough information, but let's start with an observation:

The JsonApi spec describes the use of hyphens instead of underscores. So your payload should be shipment-lines (etc). Ember uses the JsonApi as default, so you should follow this, or fix it with serializers.

For example:

export default DS.JSONAPISerializer.extend({
  keyForAttribute: function(attr, method) {
    return Ember.String.underscore(attr);
  }
});

Note that ember 'understands' that the underscores should be capitalized in your model. Your payload could be enhanced to look look this [1]:

{
"freightOrders": [{
    "id": 1,
    "comment": "Freight order comment",
    "shipments": [{
        "id": 1,
        "shipment-lines": [{
            "id": 1,
            "description": "A description",
            "package-weight": 900,
            "package-length": 1200,
            "package-height": 400,
            "package-width": 800
        }],
        "pickup-address": {
            "id": 1,
            "address": "The pickup address",
            "zip": "9000"
        },
        "delivery-address": {
            "id": 2,
            "address": "The delivery address",
            "zip": "8000"
        },
    }],
}]
}

And your shipment model:

import DS from 'ember-data';

export default DS.Model.extend({
  pickupAddress: DS.belongsTo('address', { inverse: null }),
  deliveryAddress: DS.belongsTo('address', { inverse: null }),
  shipmentLines: DS.hasMany('shipment-line', { inverse: null })
});

In your template you should be able to do a simple loop:

{{#each model.shipments as |shipment|}}
  <span>{{shipment.pickupAddress.address}}</span>
{{/each}}

[1] Better would be if you use attributes and relations in your payload to be full JSON API compliant, see for more info: http://jsonapi.org/

Upvotes: 1

Related Questions