1

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?

2
  • Could you post your model order too? Btw I would say {{#each model.shipments as |shipment|}} should work. Commented Mar 24, 2017 at 10:13
  • Thank you for responding @JacobvanLingen, I have posted code for both order and shipment model. Commented Mar 24, 2017 at 10:22

1 Answer 1

1

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/

Sign up to request clarification or add additional context in comments.

5 Comments

Thank you for your reply, I gave you an up-vote for the hyphens/underscore explanation. I have thoroughly messed that up in both back- and front end. Fixing that now. But it did not solve the problem of accessing the first shipment object in each order. Perhaps due to a poorly formulated question. What I want to achieve is to, in every '{{#each model as |order|}}', access the first shipment as '{{order.shipments.0.pickupAddress}}' if it is even possible.
@pusle: Yeah, in the each loop, use {{order.shipments.firstObject.pickupAddress}}.
Thank you, that solved it. Everywhere I looked, it either said to use shipments.0.pickupAddress or shipments.[0].pickupAddress.
the payload you recommend is not JSONAPI!
@Lux: You are right, changed my answer accordingly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.