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.
Related
-------------------------------
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}}
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.
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'),
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 two models:
App.Administrator = DS.Model.extend({
name: DS.attr('string'),
courses: DS.hasMany('course', {async: true})
});
App.Course = DS.Model.extend({
title: DS.attr('string')
})
On "edit administrator" page I want to display list of checkboxes, one for each course, so that selecting one pushes it to "model.courses", and unselecting removes it from "model.courses".
But the main question is: how do I check whether the course is already inside "model.courses"?
DS.hasMany instantiates a DS.ManyArray, which extends a DS.RecordArray, which extends a run-of-the-mill Em.ArrayProxy. You should be able to do a courses.contains(test object) to see if it's already in the collection. Adding and removing courses should just be a matter of using pushObject and removeObject:
courses.pushObject(object);
...
courses.removeObject(object);