EmberJS auto loading inverse relations? - ember.js

I have a model like:
var Survey = DS.Model.extend({
title: DS.attr('string'),
});
and:
var SurveySection = DS.Model.extend({
survey: DS.belongsTo('survey', {async:true}),
title: DS.attr('string'),
help_text: DS.attr('string'),
});
If i have a survey object, can I just do survey.get('survey_section') to get all the sections associated with a particular survey, because this isn't working? It doesn't even work if I add a survey_sections: DS.hasMany('survey_sections', {async:true}) to my survey model.
I should add that I'm using fixtures. When I release the app they'll still be used (ie so if the RESTAdapater would fix it, that's not a fix in my case):
Survey.reopenClass({
FIXTURES: [
{
"id": 1,
"title": "Favourite food"
},
{
"id": 2,
"title": "Sports"
}
]
});
and:
SurveySection.reopenClass({
FIXTURES: [
{
"help_text": "",
"id": 1,
"survey": 1,
"title": "Italian food"
},
{
"help_text": "",
"id": 2,
"survey": 1,
"title": "Team sports"
}, ...]});
Is the fixture adapter not able to retrieve related records in the reverse direction like this? If not, will I have to go the laborious route of manually getting the sections with survey=1, for example (laborious because I'll have to take this approach throughout my whole app with other models)?
Update
Specifically my failing code is (with survey 1):
this.get('survey').get('survey_sections').then(function(survey_sections) {
// survey_sections contains no objects, so objectAt(0) returns undefined.
survey_sections.objectAt(0).get('questions').then(function(questions) {
console.log('Set first question ID to ' + self.get('firstQuestionId'));
});
});
As the fixtures show there should be 2 SurveySection objects in survey_sections, but instead none are found.

I didn't want to do it, but I had to add the forward relation to the items in the Survey fixture, e.g.:
Survey.reopenClass({
FIXTURES: [
{
"id": 1,
"title": "Favourite food",
"survey_sections": [1, 2],
},
{
"id": 2,
"title": "Sports",
"survey_sections": [3],
}
]
});
and update the Survey model with:
survey_sections: DS.hasMany('survey_sections', {async:true})

Related

ember data no model was found for attribute name

I have defined a model(app/models/job.js)
import DS from 'ember-data';
export default DS.Model.extend({
status: DS.attr(),
result: DS.attr()
});
And I am trying to load it from the index controller(app/controllers/index.js)
import Ember from 'ember';
export default Ember.Controller.extend({
productName: "",
customerName: "",
startDate: "",
endDate: "",
actions: {
search: function() {
let data = this.store.find("job", '9e5ce869-89b3-4bfc-a70f-034593c21eae');
return data;
}
}
});
The HTTP response I get is:
{
"status": "OK",
"result": {
"b": 2,
"a": 2,
"see": 1,
"c": 1
}
}
How ever I get following error and warning:
WARNING: Encountered "status" in payload, but no model was found for model name "status" (resolved model name using next-gen-analytics#serializer:job:.modelNameFromPayloadKey("status"))
WARNING: Encountered "result" in payload, but no model was found for model name "result" (resolved model name using next-gen-analytics#serializer:job:.modelNameFromPayloadKey("result"))
TypeError: Cannot read property '_internalModel' of undefined
at finders.js:50
at Object.Backburner.run (ember.debug.js:224)
at ember$data$lib$system$store$$Service.extend._adapterRun (store.js:2043)
at finders.js:45
at tryCatch (ember.debug.js:56151)
at invokeCallback (ember.debug.js:56166)
at publish (ember.debug.js:56134)
at ember.debug.js:32577
at Queue.invoke (ember.debug.js:910)
at Object.Queue.flush (ember.debug.js:974)onerrorDefault # ember.debug.js:32616exports.default.trigger # ember.debug.js:56792Promise._onerror # ember.debug.js:57758publishRejection # ember.debug.js:56065(anonymous function) # ember.debug.js:32577Queue.invoke # ember.debug.js:910Queue.flush # ember.debug.js:974DeferredActionQueues.flush # ember.debug.js:770Backburner.end # ember.debug.js:160Backburner.run # ember.debug.js:228run # ember.debug.js:20238ember$data$lib$system$adapter$$default.extend.ajax.Ember.RSVP.Promise.hash.success # rest-adapter.js:831jQuery.Callbacks.fire # jquery.js:3148jQuery.Callbacks.self.fireWith # jquery.js:3260done # jquery.js:9314jQuery.ajaxTransport.send.callback # jquery.js:9718
Any suggestion will be appreciated
UPDATE
I was thinking this is kind of a bug, so I went ahead to log a bug on ember-data github repo, got the response from #wecc in an hour or so (NICE)
https://github.com/emberjs/data/issues/3683
So to fix this issue, I wrote my own serializer.
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
normalizePayload: function(payload) {
return {
'job': {
id: '9e5ce869-89b3-4bfc-a70f-034593c21eae',
status: payload.status,
result: payload.result
}
};
}
});
And now, it starts working.
OPINION I can think of why they implemented the default RESTSerializer this way, but we probably should give more information to the users on the documentation of the ember-data, otherwise, newbie who is trying to use it will get lost.
1) Your server response should have a root element with the same name, as model's. So, for single object it shuld be:
{
"job": {
"id": "<backend must provide an id, integer preferred>"
"status": "OK",
"result": {
"b": 2,
"a": 2,
"see": 1,
"c": 1
}
}
And for multiple objects:
{
"jobs": [{
"id": "<backend must provide an id, integer preferred>"
"status": "OK",
"result": {
"b": 2,
"a": 2,
"see": 1,
"c": 1
}, {/*next object*/}]
}
I tried to debug it, and I found that the code goes to rest-serializer.js and extractSingle function, and goes to the line "if (!store.modelFactoryFor(modelName)) {" and it returns "false".
extractSingle: function (store, primaryTypeClass, rawPayload, recordId) {
Ember.deprecate("`serializer.normalizePayload` has been deprecated. Please use `serializer.normalizeResponse` with the new Serializer API to modify the payload.", this.normalizePayload === JSONSerializer.prototype.normalizePayload, {
id: "ds.serializer.normalize-payload-deprecated",
until: "2.0.0"
});
var payload = this.normalizePayload(rawPayload);
var primaryRecord;
for (var prop in payload) {
var modelName = this.modelNameFromPayloadKey(prop);
if (!store.modelFactoryFor(modelName)) {
Ember.warn(this.warnMessageNoModelForKey(prop, modelName), false, {
id: "ds.serializer.model-for-key-missing"
});
continue;
}
var isPrimary = this.isPrimaryType(store, modelName, primaryTypeClass);
var value = payload[prop];

Ember data, how can i use nested(two-depth) json-format for hasMany Relationship

Generally, Ember HasMany relationship json format is follow,
{ "post" : { id:1, title:"this is title", comments:[1,2], writer: ...} }
But, i want to use next json format (because, my server return like this)
{ "post" : { id:1, title:"this is title",
comments:[
{id:1, bodytext:"blarblar...."},
{id:2, bodytext:"second blarblar...."},
], writer: ...} }
How can I use this?
Isn't there any problem in ember store relationship?
This is a job for EmbeddedRecordsMixin.
If you're implementing the server yourself and it's purpose-built for your ember application, you should consider switching to side-loading instead:
{ "post" : { id: 1,
title: "this is title",
comments: [1,2],
writer: ...
},
"comments": [ { id: 1,
bodytext: "blarblar...."
},
{ id: 2,
bodytext: "second blarblar...."
}
]
}
That way, it would be still just one request, but would work for more complicated structures (other than trees) as well.

How do I declare a `type` key on a polymorphic relationship in Ember.js?

I'm trying to learn ember.js and I have a problem with trying to use the DS.FixtureAdapter with mock data. Whenever I try to access the store I get an Ember error of:
Error while processing route: exercises Assertion Failed: Ember Data expected a number or string to represent the record(s) in the pictureExercises relationship instead it found an object. If this is a polymorphic relationship please specify a type key. If this is an embedded relationship please include the DS.EmbeddedRecordsMixin* and specify the pictureExercises property in your serializer's attrs hash.
Looking at the ember data section in the ember inspector I can see all the top level exercise data is loaded correctly, the PictureExercises and VideoExercises are not.
How do I declare a type key on a polymorphic relationship in Ember.js?
I'm at a total loss and any help would be greatly appreciated. Thanks for your time.
//Create application store
Gymbo.ApplicationAdapter = DS.FixtureAdapter;
//Set up models and relationships
Gymbo.Exercise = DS.Model.extend({
//id: DS.attr("number"), /*Ember will error if id is in model* /
name: DS.attr("string"),
description: DS.attr("string"),
pictureExercises: DS.hasMany("pictureExercise", {async: true }),
videoExercises: DS.hasMany("videoExercise", { async: true })
});
Gymbo.PictureExercise = DS.Model.extend({
//id: DS.attr("number"),
exerciseId: DS.attr("number"),
mimeType: DS.attr("string"),
picFilePath: DS.attr("string"),
picName: DS.attr("string"),
exercise: DS.belongsTo("exercise")
});
Gymbo.VideoExercise = DS.Model.extend({
//id: DS.attr("number"),
exerciseId: DS.attr("number"),
videoName: DS.attr("string"),
videoFilePath: DS.attr("string"),
videoType: DS.attr("string"),
exercise: DS.belongsTo("exercise")
});
//UsersRoute
Gymbo.ExercisesRoute = Ember.Route.extend({
model: function () {
return this.store.find("exercise");
}
});
//MOCK DATA
Gymbo.Exercise.reopenClass({
FIXTURES:
[
{
"id": 101,
"name": "Exercise 1",
"description": "Description here",
"pictureExercises": [
{
"id": 106,
"exerciseId": 101,
"mimeType": "PNG",
"picFilePath": "images\\strength",
"picName": "s001"
},
{
"id": 107,
"exerciseId": 101,
"mimeType": "JPG",
"picFilePath": "images\\strength",
"picName": s002
}
],
"videoExercises": [
{
"id": 101,
"exerciseId": 101,
"videoName": "Test",
"videoFilePath": "Video\\strength",
"videoType": "mp4"
}
]
},
{
"id": 102,
//Data removed for brevity.....
}
]
});

How to write Ember model for tree type json

I am very new to ember, can any one tell me how to write ember model for json show below. I searched lot but couldn't come up with any solution
{id:1, name: "A", children: [
{ id:1, name: "A1" },
{ id:2, name: "A2" },
{
id:3, name: "A3", children: [
{
id:1, name: "A31", children: [
{ id:1, name: "A311" },
{ id:2, name: "A312" },
]
},
]
},
]
Thanks
Have you already tried something like the following? I have not worked with ember data yet, but i imagine it to work like this:
App.Person = DS.Model.extend({
id : DS.attr("number"),
name : DS.attr("string"),
children : DS.hasMany("App.Person"),
parent : DS.belongsTo("App.Person")
});
Somehow I figure out the solution after a long time. I am answering this question because it may help others
here is the json data I have used
{"parent":[
{"id":1, "name":"A", "children_ids":[1,2]}
],
"children":[
{"id":1, "name":"A1", "children_ids":[3,4]},
{"id":2, "name":"A2", "children_ids":[5]},
{"id":3, "name":"A11"},
{"id":4, "name":"A12"},
{"id":5, "name":"A21"}
]
}
Ember model
App.Parent= DS.Model.extend({
name: DS.attr('string'),
children: DS.hasMany('App.Children')
});
App.Children = DS.Model.extend({
name: DS.attr('string'),
children: DS.hasMany('App.Children')
});
Don't forget to make plural of children is children
DS.RESTAdapter.configure(
"plurals",{
children:"children"
}
)

Ember-Data recursive hasMany association

Has anyone used ember-data to model a tree of data?
I would assume it would be something like:
Node = DS.Model.extend({
children: DS.hasMany(Node),
parent: DS.belongsTo(Node)
});
However, I have not been able to get this working which leads be to believe that either: 1) I'm just plain wrong in how I'm setting this up or, 2) it is not currently possible to model a tree using ember-data.
I'm hoping that it's the former and not the latter...
Of course it could be the JSON...I'm assuming the JSON should be of the form:
{
nodes: [
{ id: 1, children_ids: [2,3], parent_id: null },
{ id: 2, children_ids: [], parent_id: 1 },
{ id: 3, children_ids: [], parent_id: 1 }
]
}
Any tips/advice for this problem would be greatly appreciated.
There are several little things that prevent your fiddle to work:
the DS.hasMany function asks for a String as argument. Don't forget the quotes: DS.hasMany('Node')
in the fixture definition, hasMany relationships should not be postfixed by _ids or anything. Just use the plain name. For instance: { id: 42, children: [2,3], parent_id: 17 }
the length property of DS.ManyArray should be accessed using the get function: root.get('children.length')
by default, the fixture adapter simulates an ajax call. The find query will populate the record after waiting for 50ms. In your fiddle, the root.get('children.length') call comes too early. You can configure the fixture adapter so that it makes synchronous call:
App.store = DS.Store.create({
revision: 4,
adapter: DS.FixtureAdapter.create({
simulateRemoteResponse: false
})
});
Or you can load data to the store without any adapter:
App.store.loadMany(App.Node, [
    { id: 1, children: [2, 3] },
    { id: 2, children: [], parent_id: 1 },
    { id: 3, children: [], parent_id: 1 }
]);
and last one: it seems like the Ember app should be declared in the global scope (no var), and Ember-data models should be declared in the app scope (replacing var Node = ... by App.Node = ...)
Full example:
App = Ember.Application.create();
App.store = DS.Store.create({
    revision: 4
});
App.Node = DS.Model.extend({
children: DS.hasMany('App.Node'),
parent:   DS.belongsTo('App.Node')
});
App.store.loadMany(App.Node, [
{ id: 1, children: [2, 3] },
{ id: 2, children: [], parent_id: 1 },
{ id: 3, children: [], parent_id: 1 }
]);
var root = App.store.find(App.Node, 1);
alert(root.get('children'));
alert(root.get('children.length'));
This didn't work for me until I set up the inverse:
App.Node = DS.Model.extend({
children: DS.hasMany('App.Node', {inverse: 'parent'}),
parent: DS.belongsTo('App.Node', {inverse: 'children'}) });
Not sure but as per example given in ember guide
App.Post = DS.Model.extend({
comments: DS.hasMany('App.Comment')
});
The JSON should encode the relationship as an array of IDs:
{
"post": {
"comment_ids": [1, 2, 3]
}
}