I need to understand once for all why property like
isSettled
isPending
isFulfilled
are different if I’m including or not the data in my API respone.
I’m asking here this: Ember 2, Show a single loading message when the ids where included in the original response which leads me to this strange behaviour:
If I include in my API responde the data (ex: model.posts
) these properties are immediately set to true (and .isPending
to false) also if Chrome is still loading the real data (also for the first time!).
And this is a problem because I don’t know if the posts[] are empty or not and I don’t know what I can spy because something like that doesn’t work:
{{#each model.posts}}
My posts.
{{else}}
{{#if model.posts.isPending}}
<div>Loading...</div>
{{else}}
<div>Nothing to show.</div>
{{/if}}
{{/each}}
It’s always “Nothing to show.” until Chrome loads. Because .isPending
is immediately false.
Also if I use the length attributes:
{{#if (eq model.posts.length 0)}}
because the starting posts[] array and the empty one is always to length == 0.
If I loads posts differently, async, not sideloaded (but with hundreds HTTP requests, which I don’t want) it works. Ember recognize an isPending
…
Why this strange behaviour?
It looks like model.posts
is a DS.PromiseArray
. This is an Ember.ArrayProxy
mixed with Ember.PromiseProxyMixin
.
I think it’s better to think of the object as a Promise first and array second. As such, you need to invert your template’s logic.
{{#if model.posts.isPending}}
<div>Loading...</div>
{{else if model.posts.isRejected}}
<div>Failed...</div>
{{else}}
{{#each model.posts as |post|}}
My posts {{post.name}}
{{else}}
<div>Nothing to show.</div>
{{/each}}
{{/if}}
Thanks @lightblade, but this is not working.
The problem is not there.
Can you please paste your model() hook code here.
That gives us a better understanding.
Yes dear @Elisha.Ebenezer. Thanks for your answer.
This is my model():
export default Ember.Route.extend({
model(params) {
return this.store.findRecord('category', params.category_id);
}
});
Hello John,
IMHO, the reported behavior seems to be the “right” behavior and as per design
By looking at your other related post, it is obvious that you are using a JSON API(ish) backend.
Now, whenever a JSON response document contains included
, it is treated as compound
document and that all the data
in the included
section is expected/considered to be complete data, unless you ask for sparse fields.
JSON API specification details out on fetching related records and Compound Documents
With that, in your case, when a compound response
for category is received, it already contains all the posts and there is no need to resolve posts.
Hence, you’ll never get to else
part of each
.
If you really want to have lazy loading, you might want to do away with includes
and have the relationship definitions with async : true
HTH
Dear @lightblade, sorry, I’m using your template (with isPending
or isSettled
or isFulfilled
) but now I see a little “blink” betweeen <div>Nothing to show.</div>
and <div>Loading...</div>
…
Maybe model.posts.isPending
is already immediately true
then false, loading… and then first part of each is Ok.
How can I avoid that “blink” / “flash”?
There are two solutions to this:
- Make the Promise somehow synchronously resolve. If the promise is resolved before the run loop flushes, you won’t see the blink.
- Make the blink last longer to give users easier time to adjust. Just add a 500ms delay in the promise resolve.
Any example of 1? The 2, I think is not good to add time… generally… No?
DS.PromiseArray.create({
promise: RSVP.resolve(value) // <-- if value is resolved here, then we have no flashes
})
You can even use {{debugger}}
to inspect value that might change.
But I need it in model()
?