I dont understand how ember loads related models.
Lets say thats my model:
export default DS.Model.extend({
title: DS.attr('string'),
description: DS.attr('string'),
states: DS.hasMany('state', {async: true})
})
I load this on of my outer routes. When navigating though an ember-app (into nested routes), model-contexts are often provided for routes not by the model-hook of the route but with the link-to helper (when using dynamic-segments, the model-hook will be ignored). When the target route has something in its template like {{#each model.states as |state|}}
, ember will load automatically the related model-entrys from (in that case)the state-model. (How and why? - Just because of the each
in the template?
When accesing an dynamic-route directly, the model is not given and the model-hook of the dynamic route will be called. So loading my model is easy: just override the model hook and load record with the url parameter (return this.store.find('item', {title: params.item_title})
). But no related models will be loaded. How can I do that manually and what (and when) is the way ember do it by default?
ember-data allows you to define relationships (currently only belongsTo
and hasMany
) with async
option set to true
or false
. Based on this option, after fetching the model from the API (via find
method), ember-data will expect relationships object either directly in the response JSON or not. You have async: true
(which is rather a common and supported way of handling relationships), therefore ember-data assumes that in your JSON response it gets the id
s of states, but not necesseraily the states themselves.
If you define your hasMany
as async: true
, it always returns promise. It means, that if you make something like this:
this.get("item").get("states")[0]
Will not work, as get("states")
will not return an array, but the promise to fetch this array. However, Handlebars are smart (as the get
and set
methods of Ember) and it can find out what is a promise and wait for it to resolve before using it content. Therefore if your template contains:
{{#each model.states as |state|}}
Handlebars finds out that states
is promise, wait for it to resolve, and after resolve they use its content as an array. Very similar behaviour can be found using belongsTo
method. Assuming that your item
has one state
, if you use the code as follows:
this.get("item.state.somePropertyOfState")
Even if you did not fetched the state
and currently you don't know what is the somePropertyOfState
value, ember get
will find out it's a promise and fetch it for you automatically.
There are couple of ways to do it.
First one is to explicitly fetch them in ember code:
this.get("item.states").then(function(states) {
# now you have fetched the states that the item has, and moreover
# they are accessible in states variable
});
Second, you can let Ember do it automatically for you as I described formerly (e.g. via template).
Third, you can send the relationships with your response using a mechanism called sideload. This will significantly reduce the number of API requests. When you allow ember fetch your relationships, ember is performing one request per one relationship object, which means that if you have ten states
that belongs to item
, the API will be hit ten times. However, if you sidelod the states
while fetching the item
, the request will be sent only once. Take a look here to get more info about that.
Sorry for a long post, but I hope that I clarifed a bit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With