I have problem defining the relationship between my models in order to get cascading property.
I would like to MapLineString to be deleted when Trail is deleted or Draw is deleted. But I DO NOT want Trail to be deleted when MapDraw or MapLineString gets deleted.
Relationship between the models is :
Trail can have one Trailer, one Team and one mapDraw
MapDraw can have many MapLineString
MapLineString can belongs to Trail AND/OR MapDraw
Trail = DS.Model.extend({
Trailer: DS.belongsTo('mapLinestring', {async: true, inverse: 'trail'}),
Team: DS.belongsTo('mapLinestring', {async: true, inverse: 'trail'}),
mapDraw: DS.belongsTo('mapDraw', {async: true}),
});
MapDraw = DS.Model.extend({
lineStrings: DS.hasMany('mapLinestring', {async: true}),
trail: DS.belongsTo('mtgTrail')
});
MapLineString = DS.Model.extend({
trail: DS.belongsTo('mtgTrail'),
mapDraw: DS.belongsTo('mapDraw'),
});
Assertion Failed: You defined the 'trail' relationship on
mantrailling#model:map-linestring:, but you defined the inverse
relationships of type mantrailling#model:mtg-trail: multiple times.
Look at
http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses
for how to explicitly specify inverses
Looking at what youve written at the beginning of the post it sounds like
A should be:
export default DS.Model.extend({
bees: DS.hasMany('B', {async: true, inverse: 'abees'}),
cees: DS.hasMany('C', {async: true}), //doesnt need an inverse as you are getting all the ones that belong to A
});
B should be:
export default DS.Model.extend({
cees: DS.hasMany('C', {async: true, inverse: 'bcees'}),
abees: DS.belongsTo('A')
});
and then in C you have two model properties called the same thing
export default DS.Model.extend({
acees: DS.belongsTo('A'),
bcess: DS.belongsTo('B')
});
Your naming conventions also make it quite confusing. Why not just name the attrs of the models something thats relevant to what they represent?
Ok, I found out what the problem was.
I have been using Localstorage adapter, which does not work with {async: true}.
The records were not persisted on the parent side.
Related
Consider the following simple models...
//models/invoice.js
export default DS.Model.extend({
//created_by: DS.attr('number'), //points to a user.id
created_by: DS.belongsTo('user', {async: true, inverse: created_by}),
//approved_by: DS.attr('number'), //also points to a user.id
approved_by: DS.belongsTo('user', {async: true, inverse: approved_by}),
});
//models/user.js
export default DS.Model.extend({
name: DS.attr('string')
created_by: DS.belongsTo('invoice', {async: true, inverse: 'created_by'}),
approved_by: DS.belongsTo('invoice', {async: true, inverse: 'approved_by'})
});
And relevant JSON...
{
"invoices":
[
{
"id": "2",
"created_by": "103",
"approved_by": "109",
.....
I am trying to get the Names values for each of the ID values in any given Invoice record.
# | Created | Approved
--------------------------
2 | Jim | Bobby
3 | Sue | Betty
I can get the approved_by relationship to populate data in my template....
{{item.approved_by.id}} {{item.approved_by.name}}
but not created_by...
{{item.created_by.id}} {{item.created_by.name}}
I can see some data being rendered in the template then it goes away.
I can see the correct requests sent off to the API...
http://localhost:4200/RESTAPI/v1/users/110
http://localhost:4200/RESTAPI/v1/users/200
My question: What am I doing wrong?
This is where Ember relationships come into play. In your particular example, you need to tell Ember that your Invoice model belongs to your User model. And, vice versa, your User model can have many invoices related to it.
The actual syntax for this can be found here:
http://emberjs.com/guides/models/defining-models/#toc_one-to-many
Once you wire that up properly, you can do something like:
invoice.get('user.name')
I have a pretty basic setup where I'm trying to format a date in my Controller. The problem is I can't access it in the formattedStart function below, whereas I CAN access it in the summaryRowAction handler. This is baffling me, because console.logging this in both places gives the same result. But for some reason inside of formattedStart, this.get('model.startDate') is undefined.
App.SummaryRowController = Ember.ObjectController.extend({
formattedStart: function(){
console.log(this.get('model.startDate');)
return this.get('model.startDate');
}.property(),
actions: {
summaryRowAction: function(){
console.log(this.get('model.startDate'));
}
}
});
Here is my model and my template (in Jade) for reference:
App.PricingSummary = DS.Model.extend({
startDate: DS.attr(),
endDate: DS.attr(),
days: DS.hasMany('day', {async: true}),
property: DS.belongsTo('property', {async: true})
});
script(type="text/x-handlebars", data-template-name="summaryRow")
.summaries__summary("{{action 'summaryRowAction'}}")
.summaries__summary--item{{formattedStart}} — {{endDate}}
It's because the first (and only) time that the property is evaluated, model is actually null. You need to specify startDate as a dependency in the property so Ember knows to re-evaluate when the data changes. Also, you don't need model.* in an object controller, the properties are automatically delegated to content/model
So:
formattedStart: function(){
console.log(this.get('startDate');)
return this.get('startDate');
}.property('startDate'),
Say I have two Ember Data models: competition and participant
My competition model stores the following data: date, first, second and third. The first, second and third properties will all store IDs of the unique competitors who came in first, second and third place.
My participant model stores the following data: name, surname and competition
Participants only compete in one competition, so the participant model doesn't need a hasMany relationship on competition.
How do I model this in Ember Data?
Here's what I thought might work:
// app/models/competition.js
export default DS.Model.extend({
rev: DS.attr('string'),
date: DS.attr('date', {defaultValue: function() { return new Date(); }}),
first: DS.belongsTo('participant'),
second: DS.belongsTo('participant'),
third: DS.belongsTo('participant')
});
// app/models/participant.js
export default DS.Model.extend({
rev: DS.attr('string'),
name: DS.attr('string'),
surname: DS.attr('string'),
competition: DS.belongsTo('competition')
});
The problem is that the competition key on participant.js requires an explicit inverse, and there's no way of knowing which of the three keys on competition it may relate to.
How should I be specifying my inverses? Do both the competition and participant models require explicit inverses? If so, what should they be? Is this kind of data structure even possible in Ember Data? Should I use a different approach altogether?
Please weigh in. I've turned this problem around in my head for hours, and none of my workarounds have succeeded.
I haven't used ember-data polymorphic association myself, but I believe a polymorphic belongsTo association might suit your needs. My answer is adapted from this blog post
. Also check this two tutorials: http://www.toptal.com/emberjs/a-thorough-guide-to-ember-data and http://blog.unspace.ca/post/107228551852/luke-galea-on-ember-data-polymorphic-associations
//app/models/competition.js
export default DS.Model.extend({
rev: DS.attr('string'),
date: DS.attr('date', {defaultValue: function() { return new Date(); }}),
participant: DS.belongsTo("particpant", {polymorphic: true, async: true})
});
// app/models/participant.js
export default DS.Model.extend({
rev: DS.attr('string'),
name: DS.attr('string'),
surname: DS.attr('string'),
competition: DS.belongsTo('competition')
});
// app/models/first.js
import Participant from '../participant';
export default Participant.extend({
});
// app/models/second.js
import Participant from '../participant';
export default Participant.extend({
});
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 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.