I'm using firebase in combination with Ember CLI. I have the following setup:
ember.debug.js:6401 DEBUG: Ember : 2.4.5
ember.debug.js:6401 DEBUG: Ember Data : 2.5.1
ember.debug.js:6401 DEBUG: Firebase : 2.4.2
ember.debug.js:6401 DEBUG: EmberFire : 1.6.6
ember.debug.js:6401 DEBUG: jQuery : 2.2.3
I have two simple models
<!-- app/models/user.js -->
import Model from 'ember-data/model';
export default Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
email: DS.attr('string'),
profile: DS.belongsTo('profile', {async: true})
});
And a second model for my profile
<!-- app/models/profile.js -->
import Model from 'ember-data/model';
export default Model.extend({
companyName: DS.attr('string'),
user: DS.belongsTo('user', {async: true})
});
I have the following profile route:
<!-- app/routes/profile.js -->
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return this.store.query('user', { orderBy: 'email', equalTo: this.get('session.currentUser.email')}).then(function(user){
console.log(user);
return user;
});
}
});
I check if the current session email address is equalTo a email address in the database. And return the user objet. This is working. (don't know if this is the right way to do this?)
In my profile handlebars template i have the following code.
<!-- app/templates/profile.hbs -->
{{#each model as |user|}}
{{user.firstName}}
{{user.lastName}}
{{user.profile}}
{{/each}}
This returns the following on screen:
frank spin <DS.PromiseObject:ember545>
My guess is that the relationship data has not yet been received. I don't know how to solve this issue. And second question: Is my checking for the current logged in user the right way?
You're correct that the relationship data has not been received. But if you write your template like this, you should still see the profile information when it loads:
{{#each model as |user|}}
{{user.firstName}}
{{user.lastName}}
{{user.profile.companyName}}
{{/each}}
The goal of promise objects (and promise arrays) is to allow you to bind data in Ember before it's loaded, and have those bindings update once the promise resolves. This is great for secondary-importance information, which can safely be rendered after the rest of the page loads.
If you try to render your profile
model properties when the promise has not resolved, you'll get a blank space. You can display loading state information using the isPending
property:
{{#each model as |user|}}
{{user.firstName}}
{{user.lastName}}
{{#if user.profile.isPending}}
<span class="spinner">…</span>
{{else}}
{{user.profile.companyName}}
{{/if}}
{{/each}}
And you can also use the isRejected
property to detect API failures, and allow users to retry.
If this asynchronous behaviour is not what you want, you can force the relationship promise to resolve before rendering the template in the afterModel
hook of your route:
export default Ember.Route.extend({
model() {
return this.store.query('user', { orderBy: 'email',
equalTo: this.get('session.currentUser.email')});
},
afterModel(users) {
return Ember.RSVP.all(users.invoke('get', 'profile');
}
});
(With a simpler single model, you could just write return model.get('profile')
in the afterModel
hook.)
Any promise returned from afterModel
will block loading of the route until it resolves. Then your template will always have the profile of the user available when rendering.