-------------------------------
Ember : 1.13.11
Ember Data : 1.13.15
Firebase : 2.3.2
EmberFire : 1.6.3
jQuery : 1.11.3
-------------------------------
I've got two endpoints in my firebase app. /employees and /subjects. In my ember app I want to add subjects to an employee (employees/$id/subjects). The problem is, I don't know how to load all my subjects from /subjects so I can add them to my array.
This is my routes:
Router.map(function() {
this.route('dashboard');
this.route('employees', function() {
this.route('employee', { path: '/:id'});
});
});
And this is my model
export default Ember.Route.extend({
model(params) {
return this.store.findRecord('employee', params.id);
}
});
I've tried various things to get this to work, creating a subroute this.route(employee, function(){ this.route('subjects') }, loading a second model in my employee model, none of which has worked. I'm new to ember so I might have gotten some things mixed up. Any helps is appreciated.
EDIT
Employee model
export default DS.Model.extend({
name: DS.attr('string'),
position: DS.attr('string'),
accessoryPosition: DS.attr('string'),
education: DS.attr('string'),
experience: DS.attr('string'),
imgUrl: DS.attr('string'),
subjects: DS.hasMany('subject', {async: true})
});
Subject Model
export default DS.Model.extend({
name: DS.attr('string')
});
To maybe describe my intentions a bit better, here is the flow I want:
User selects an employee, employees info is shown along with a list of subjects assigned to that employee. But I also need the full list of subjects available, if I want to assign a new subject to an employee. Hence my question. Hope this makes sense
Okay, then you can do this in your Route:
export default Ember.Route.extend({
model(params) {
return Ember.RSVP.hash({
employee: this.store.findRecord('employee', params.id),
subjects: this.store.findAll('subject')
});
}
});
then in your template:
{{#each employee.subjects as |subject|}}
{{!these are your employee subjects}}
{{subject.name}}
{{/each}}
{{#each subjects as |subject|}}
{{!these are all your subjects}}
{{subject.name}}
{{/each}}
Related
While experimenting with ember and ember-localforage-adapter I noticed a strange behaviour.
ember.debug.js:4888DEBUG: Ember : 1.12.0
ember.debug.js:4888DEBUG: Ember Data : 1.0.0-beta.18
ember.debug.js:4888DEBUG: jQuery : 1.11.3
I have three models:
/app/models/ledger.js
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
purchases: DS.hasMany('purchase', {async: true}),
players: DS.hasMany('player', {async: true}),
});
/app/models/purchase.js
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
amount: DS.attr('number'),
ledger: DS.belongsTo('ledger', {async: true}),
player: DS.belongsTo('player', {async: true})
});
/app/models/player.js
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
balance: DS.attr('number'),
ledger: DS.belongsTo('ledger',{ async: true }),
purchases: DS.hasMany('purchase', {async: true}),
});
and a simple route:
/app/routes/purchase.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
return this.store.find('purchase', params.purchase_id);
}
});
My experimental template is
/app/templates/purchase.hbs
name: {{model.name}}
<br>
amount: {{model.amount}}
<br>
player: {{model.player.name}}
and it works showing me all invoked attributes. But if I add another line like
name: {{model.name}}
<br>
amount: {{model.amount}}
<br>
player: {{model.player.name}}
<br>
ledger: {{model.player.ledger.title}}
it shows the name of the player for just an instant and never shows the ledger title. How should load in the store the requested record to have them available in my template?
After reading this I added the property payer to the purchase model:
payer: function(){
return DS.PromiseObject.create({
promise: this.get( 'player' )
});
}.property('')
to be used in the template instead of player:
<h3>show purchase</h3>
model.name: <strong>{{model.name}}</strong>
<br>
model.amount: <strong>{{model.amount}}</strong>
<br>
<br>
model.payer.name: <strong>{{model.payer.name}}</strong>
<br>
model.payer.ledger.title: <strong>{{model.payer.ledger.title}}</strong>
<br>
<br>
model.player.name: <strong>{{model.player.name}}</strong>
<br>
model.player.ledger.title: <strong>{{model.player.ledger.title}}</strong>
This approach is very similar to the one suggested by Artych but, maybe because of my Rails background, I prefer to access an associated record from anywhere by the model and not by the controller associated to the route
The following gif (download it if don't see the animation) show the behaviour of both:
Can someone explain what happen? Why model.player.name disappear at the time when model.plyer.ledger.title appear? What's the difference from the template point of view between payer and player considering that both return a DS.PromiseObject?
You could try to resolve model.player.ledger in afterModel hook:
afterModel: function(model) {
var controller = this.controllerFor('purchase');
model.get('player').then(function(player) {
controller.set('player', player);
return player.get('ledger');
}).then(function(ledger){
controller.set('playerLedger', ledger);
}, function(error) {
console.log("promise is not resolved", error);
});
}
In template
{{player.name}} | {{playerLedger.title}}
I think you could see why model.player.ledger is not resolved or it could be empty.
You have typo in player model. Should be:
//app/models/player.js
import DS from 'ember-data';
export default DS.Model.extend({
// ...
ledger: DS.belongsTo('ledger', { async: true }),
//not ledger: DS.belongsTo({ async: true }),
});
Thanks in advance for any help.
I'm having a strange problem with a simple Ember app where, after deploying to Heroku, my models only make the REST call after the index route for the model is hit.
For example, I have two models: Resort and Forecast. Each have a belongsTo relationship, so every Resort has a Forecast and vice versa. In the resort template, there's a link to the corresponding forecast. When clicked, it properly routes to the forecast, however all the attributes in the forecast are undefined because it never made the API call to retrieve the forecasts JSON blob. I can watch the network tab in Chrome tools to verify this. When I navigate to /forecasts, the REST call is made, and the data is populated.
For whatever reason, all the API calls are made as I would expect. Once deployed to Heroku, this isn't the case.
This app is using ember-cli, and the relevant code follows:
/adapters/application.js
import DS from "ember-data";
var ApplicationAdapter = DS.ActiveModelAdapter.extend({
host: 'http://api.firstchair.io',
buildURL: function() {
var base;
base = this._super.apply(this, arguments);
return "" + base + ".json";
}
});
export default ApplicationAdapter;
/models/resort.js
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
state: DS.attr('string'),
latitude: DS.attr('string'),
longitude: DS.attr('string'),
region: DS.attr('string'),
token: DS.attr('string'),
weather: DS.attr('string'),
temperature: DS.attr('string'),
last_24_hours_snowfall: DS.attr('string'),
last_48_hours_snowfall: DS.attr('string'),
last_72_hours_snowfall: DS.attr('string'),
wind: DS.attr('string'),
conditions: DS.attr('string'),
baseDepth: DS.attr('string'),
humanReadableWeather: DS.attr('string'),
forecast: DS.belongsTo('forecast'),
fullDescription: function() {
return this.get('name') + ', ' + this.get('state');
}.property('name', 'state'),
currentSnowfall: function() {
return (this.get('last_24_hours_snowfall') || 0) + '"';
}.property('last_24_hours_snowfall'),
hasWind: function() {
return this.get('wind') > 0;
}.property('wind')
});
/models/forecast.js
import DS from 'ember-data';
export default DS.Model.extend({
startsAt: DS.attr('string'),
endsAt: DS.attr('string'),
weather: DS.attr('array'),
highs: DS.attr('array'),
lows: DS.attr('array'),
resort: DS.belongsTo('resort'),
days: function() {
var weather = this.get('weather');
var highs = this.get('highs');
var lows = this.get('lows');
if (!weather) { return []; }
return weather.map(function(currWeather, index) {
return {
weather: currWeather,
high: highs[index],
low: lows[index],
daysSince: index
};
});
}.property('weather', 'highs', 'lows')
});
/routes/resort.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
var resort = this.store.find('resort', params.resort_id);
console.log(resort);
console.log(resort.forecast);
return resort;
}
});
/routes/resorts.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.findAll('resort');
}
});
/routes/forecast.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
console.log('hello');
return this.store.find('forecast', params.forecast_id);
}
});
/routes/forecasts.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.findAll('forecast');
}
});
Is there something I should be doing to ensure that the data is loaded eagerly?
You can look at the code in its entirety at: https://github.com/firstchair-io/webapp
Any insight into what might be going wrong would be greatly appreciated. Thank you.
It sounds like the relationships are not being sideloaded from the backend server. So the records contain an array of ID's in the hasMany fields, but the data itself is not sent automatically. To cause Ember Data to load the associated records, set {async: true} on the relation.
I'm trying to set up a hasMany relationship between two models and a hasOne (belongsTo in the current version of Ember Data) between the hasMany and hasOne.
I'm working with Ember Data and have a made a RESTful API that works according to Ember's conventions. All the classes can be queried individually.
Bookmark = hasMany -> Termbinding
Termbinding = belongsTo -> Term
Term = belongsTo -> Termbinding
So the goal is to fetch a Bookmark and get the Terms that are attached to it through the Termbinding. I would already be pretty happy to get the Bookmark to Termbinding relation working. I went through all questions posted on here, sadly enough that didn't work.
Router.js
var Router = Ember.Router.extend();
Router.map(function() {
this.resource('bookmarks', { path:'bookmarks'});
this.resource('bookmark', { path:'bookmarks/:bookmark_id' });
this.resource('termbindings', { path:'termbindings' });
this.resource('termbinding', { path:'termbindings/:termbinding_id' });
});
export default Router;
Bookmark.js
var Bookmark = DS.Model.extend({
url: DS.attr('string'),
description: DS.attr('string'),
visits: DS.attr('number'),
termbinding: DS.hasMany('termbinding')
});
export default Bookmark;
Termbinding.js
var Termbinding = DS.Model.extend({
bookmarkId: DS.attr('number'),
termId: DS.attr('number'),
termOrder: DS.attr('number'),
bookmarks: DS.belongsTo('bookmark')
});
export default Termbinding;
I hope someone can help me because this is preventing me from using Ember for my bookmark application. Thanks in advance.
It might be wise to explicitly specify your inverses, i.e.
var Termbinding = DS.Model.extend({
bookmarkId: DS.attr('number'),
termId: DS.attr('number'),
termOrder: DS.attr('number'),
bookmarks: DS.belongsTo('bookmark', { inverse: 'termbinding' })
});
export default Termbinding;
var Bookmark = DS.Model.extend({
url: DS.attr('string'),
description: DS.attr('string'),
visits: DS.attr('number'),
termbinding: DS.hasMany('termbinding', { inverse: 'bookmarks' })
});
export default Bookmark;
Ember Data will try to map inverses for you, however, it is not without faults. It could possibly be that your pluralization of 'bookmarks' on a DS.belongsTo relationship is throwing off its automatic inverse mapping. Typically for belongsTo you would use the singular, 'bookmark'. Conversely, your hasMany would be termbindings: DS.hasMany('termbinding')
Also, if you could show where you're invoking the models that would be greatly appreciated. Typically I find that creating a JSbin at emberjs.jsbin.com helps me isolate the problem and also provides a collaborative space to debug and experiment.
I'm having a ton of trouble with updating a model in my Ember application. I can't seem to find good documentation that describes how to update my app. The following code is what I'm trying. This sends an update to /playlists/:playlist_id, unfortunately it doesn't send the updated songs as well... is there some callback for pushObject that I can't find? Am I trying trying to save the wrong thing?
App.PlaylistIndexController = Ember.ObjectController.extend({
actions: {
addSong: function(song) {
songs = this.get('songs');
songs.pushObject(song);
this.get('model').save();
}
}
});
App.Playlist = DS.Model.extend({
name: DS.attr('string'),
songs: DS.hasMany('song'),
});
App.Song = DS.Model.extend({
name: DS.attr('string'),
artist: DS.attr('string'),
playlist: DS.belongsTo('playlist'),
});
I have a system where I want users to add flags (hashtags) to items. Here's my models:
Social.Item = DS.Model.extend({
source: DS.belongsTo ('source'),
url: DS.attr (),
post_timestamp: DS.attr(),
summary: DS.attr(),
item_flags: DS.hasMany('item_flag', {async: true})
});
Social.Flag = DS.Model.extend({
kind: DS.attr(),
name: DS.attr(),
item_flags: DS.hasMany('item_flag', {async: true})
});
Social.ItemFlag = DS.Model.extend({
item: DS.belongsTo('item', {async: true}),
user: DS.belongsTo('user', {async: true}),
flag: DS.belongsTo('flag', {async: true}),
});
Here's the relevant handlebars code:
{{#each item in site.sorted_items itemController="item"}}
{{{item.summary}}}
{{#each item_flag in item.item_flags}}{{item_flag.flag}}*FF*{{/each}}
{{/each}}
The system outputs a few FF tags for each item - there's definitely item_flag elements in the database, and I can see the calls on my REST endpoint - the system is requesting the item_flags from the database. It just seems like the object on the other side of the belongsTo relationship isn't available here. I tried extending the ItemFlag model to contain this code:
flag_string: function() {
return this.get('flag').then(function (data) {return data.get('name')});
}.property('flag')
But that just throws a NPE - this.get('flag') on the ItemFlag model returns null. There seems to be some mention of an "embed: always" defined on the adapter, but (a) that's from pre- ember-data-beta days, and (b) it didn't help (also, my records aren't embedded).
What I want to do in the general case here is figure out how to look at a model's parent model, as defined by the relationships in the database.
Turns out, I fell afoul of the new ember-data serializer expectations. My item_flag serializer was responding with json that looked like {id: 1, flag_id:1, user_id:1} when what it should have looked like was {id: 1, flag:1, user:1}. This caused (apparently), the item_flag to get created without the proper parameters.