I have a model named 'someModel' is as follows
import DS from 'ember-data';
export default DS.Model.extend({
type: DS.attr('string'),
email: DS.attr('string'),
days: DS.attr('number'),
isInstant: DS.attr('boolean'),
cutHours: DS.attr('number')
});
and by default I need an array of 4 records of this model with default values as follows
"someModel": [{
"type": "Booking",
"email": "sunny.wayne#some.com,mahela.jayawardane#some.com",
"isInstant": true,
"cutHours": 72,
"days": -1
},
{
"type": "Booking",
"email": "",
"isInstant": false,
"cutHours": 72,
"days": -1
},
{
"type": "Arrival",
"email": "mahela.jayawardane#some.com",
"isInstant": false,
"cutHours": 72,
"days": 1
},
{
"type": "Cancellation",
"email": "sunny.wayne#some.com",
"isInstant": false,
"cutHours": 72,
"days": -1
}
]
Whats the ideal way to do this? I looked at the createRecord, but only one record can be created at a time. My backend logic expecting the data to be in the above format and I will also have to update the 4 records that are created depending on the user action.
Wrap your "someModel" with another model in a hasMany relationship.
Create another model, lets call it "parentModel" for our understanding.
In its model definition, add the "someModel" as a property with hasMany relation.
parentModel.js
export default DS.Model.extend({
someModel: DS.attr('someModel')
});
Now create a parentModel record and add as many as someModel records to it and save the parentModel.
let pModel = this.get("store").createRecord("parentModel");
pModel.get("someModel").addObject(this.get("store").createRecord("someModel", {
type: "Booking",
email: "sunny.wayne#some.com,mahela.jayawardane#some.com",
isInstant: true,
cutHours: 72,
days: -1
}));
pModel.save();
Looking at the JSON structure that you had provided, you need to use JSONSerializer and EmbeddedRecordsMixin to get the someModel json in your response.
Also make sure that "id" are retured for record of someModel in the response.
The request formed by ember would be like this
{
"someModel": [{
"type": "Booking",
"email": "sunny.wayne#some.com,mahela.jayawardane#some.com",
"isInstant": true,
"cutHours": 72,
"days": -1
}]
}
Related
I'm using RESTAdapter and trying to figure out how to access sideloaded data.
A sample of the payload is:
{
"category": {
"categoryName": "test category",
"id": 6,
"products": [
4419,
502,
3992
]
},
"products": [{
"description": "Whatevs",
"id": 4419,
"name": "Product 1",
"price": 114.95,
"skuid": "S21046"
}, {
"description": "Whatevs",
"id": 502,
"name": "Product 2",
"price": 114.95,
"skuid": "SOLS2594"
}, {
"description": "Whatevs",
"id": 3992,
"name": "Product 3",
"price": 114.95,
"skuid": "S21015"
}]
}
I can see 'category' and 'product' data models (and data) in the ember inspector, so I know they are being loaded.
I can even access the products in the template model.products. BUT I can't access model.products in the route's setupController. The error I get is:
TypeError: Cannot read property '_relationships' of undefined
This is really perplexing me! My route model hook is:
model(params) {
return this.get('store').queryRecord('category', {
id: params.id
})
}
The setupController hook (that causes the error) is:
setupController(controller, model) {
controller.set('results', model.products);
}
The 'category' model:
export default DS.Model.extend({
products: hasMany('product'),
categoryName: attr('string')
});
The 'product' model:
export default DS.Model.extend({
name: attr('string'),
skuid: attr('string'),
price: attr('number'),
description: attr('string')
});
My template (which works, if I remove the 'setupController' hook from the route):
{{#each model.products as |product|}}
{{product.name}} {{product.skuid}}<br />
{{/each}}
I'd like to be able to access model.products from the route's setupController so I can call it something else. Any help appreciated.
Relationship returns Promises. so to get the result you need to use then. but accessing it in template will work because template is by default promise aware.
setupController(controller, model) {
//controller.set('results', model.products);
model.get('products').then((result) => {
controller.set('results',result);
});
}
Please give read on relationships as promises guide.
I have an issue when trying to display a list of objects where each object has nested objects and there is even another level of objects in those objects. The API-respons gives me this (simplified) JSON-data where there are many freight orders:
{
"freightOrders": [{
"id": 1,
"comment": "Freight order comment",
"shipments": [{
"id": 1,
"shipment_lines": [{
"id": 1,
"description": "A description",
"package_weight": 900,
"package_length": 1200,
"package_height": 400,
"package_width": 800
}],
"pickup_address": {
"id": 1,
"address": "The pickup address",
"zip": "9000"
},
"delivery_address": {
"id": 2,
"address": "The delivery address",
"zip": "8000"
},
}],
}]
}
What I want is to display a list of all freight orders, and for the time being, access directly the first shipments-line for each order. In Handlebars I have tried
{{#each model as |order|}}
<span>
{{order.shipments.0.pickup_address.address}},
{{order.shipments.0.pickup_address.zip}}
</span>
{{/each}}
and
{{#each model as |order|}}
{{#each order.shipments as |shipment|}}
<span>
{{shipment.pickup_address.address}},
{{shipment.pickup_address.zip}}
</span>
{{/each}}
{{/each}}
Edit: Here is the order model as requested:
import DS from 'ember-data';
export default DS.Model.extend({
comment: DS.attr('string'),
shipments: DS.hasMany('shipment', { inverse: null })
});
and the shipment model for good measure:
import DS from 'ember-data';
export default DS.Model.extend({
pickup_address: DS.belongsTo('address', { inverse: null }),
delivery_address: DS.belongsTo('address', { inverse: null }),
shipment_lines: DS.hasMany('shipment-line', { inverse: null })
});
Whatever I try to do, I am not able to access shipments element or any nested objects of the order object.
I can mention that I have also tried to create the shipments part as a component and pass order.shipments to the component, but to no prevail.
Searching SO and google does not reveal any hints only some examples of how to do nested each in ember 1.x
So, how can one access nested objects in an each-loop in Handlebars and Ember Data?
I don't know if I got enough information, but let's start with an observation:
The JsonApi spec describes the use of hyphens instead of underscores. So your payload should be shipment-lines (etc). Ember uses the JsonApi as default, so you should follow this, or fix it with serializers.
For example:
export default DS.JSONAPISerializer.extend({
keyForAttribute: function(attr, method) {
return Ember.String.underscore(attr);
}
});
Note that ember 'understands' that the underscores should be capitalized in your model. Your payload could be enhanced to look look this [1]:
{
"freightOrders": [{
"id": 1,
"comment": "Freight order comment",
"shipments": [{
"id": 1,
"shipment-lines": [{
"id": 1,
"description": "A description",
"package-weight": 900,
"package-length": 1200,
"package-height": 400,
"package-width": 800
}],
"pickup-address": {
"id": 1,
"address": "The pickup address",
"zip": "9000"
},
"delivery-address": {
"id": 2,
"address": "The delivery address",
"zip": "8000"
},
}],
}]
}
And your shipment model:
import DS from 'ember-data';
export default DS.Model.extend({
pickupAddress: DS.belongsTo('address', { inverse: null }),
deliveryAddress: DS.belongsTo('address', { inverse: null }),
shipmentLines: DS.hasMany('shipment-line', { inverse: null })
});
In your template you should be able to do a simple loop:
{{#each model.shipments as |shipment|}}
<span>{{shipment.pickupAddress.address}}</span>
{{/each}}
[1] Better would be if you use attributes and relations in your payload to be full JSON API compliant, see for more info: http://jsonapi.org/
I'm using Ember's RESTAdapter and have a pretty standard polymorphic relationship:
// models/order.js
import DS from 'ember-date';
export default DS.Model.extend({
transferableItem: DS.belongsTo('transferable-item', { polymorphic: true })
});
// models/transferable-item.js
import DS from 'ember-date';
export default DS.Model.extend({
order: DS.belongsTo('order')
});
// models/ticket.js
import TransferableItem from './transferable-item';
export default TransferableItem.extend();
My JSON looks like this:
{
"orders": [{
"id": 111,
"transferableItem": 999
"transferableItemType": "Ticket"
}],
"tickets": [{
"id": 999
}]
}
Looking in Ember Inspector, both Orders and Tickets properly load. However, the link between the two of them is broken. I get this error:
You looked up the 'transferableItem' relationship on a 'order' with id
999 but some of the associated records were not loaded. Either make
sure they are all loaded together with the parent record, or specify
that the relationship is async (DS.belongsTo({ async: true }))
According to Ember Inspector, there are no transferable-items loaded, so in a way, this error makes sense. However, since this is a polymorphic relationship, shouldn't it just try to use the associated Ticket, which is in fact loaded?
Kept on digging, and discovered that the syntax needs to change when the record is embedded. The JSON should look like this:
{
"orders": [{
"id": 111,
"transferableItem": {
"id": 999
"type": "ticket"
}
}],
"tickets": [{
"id": 999
}]
}
Currently developing an app using Ember-cli and having some dificulties with models with 2 words and relationships.
Model residents-profile
//models/residents-profile.js
DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
picture: DS.attr('string'),
phone: DS.attr('string'),
gender: DS.attr('string'),
residentsAccount: DS.belongsTo('residentsAccount')
}
** Model Residents-account **
//models/residents-account.js
DS.Model.extend({
email: DS.attr('string'),
password: DS.attr('string'),
profileId: DS.attr('number'),
residentsProfile: DS.belongsTo('residentsProfile', this.profileId),
});
the model hook on the residents route:
//routes/residents.js
model: function() {
return Ember.RSVP.hash({
residentsProfile: this.store.find('residentsProfile'),
residentsAccount: this.store.find('residentsAccount')
})
}
As soon as I try and fetch just the residents profile, i get an error "residents.index Cannot read property 'typeKey'"
But if I remove the relationship key from residents-profile and call only the residents profile the data is fetched correctly.
I'm using the RESTAdapter and a Restful API,
The models are being returned separately and the response from the server is as follows:
GET /residentsProfile
{
"residentsProfiles": [{
"id": 20,
"picture": null,
"phone": null,
"firstName": "Rocky",
"lastName": "Balboa",
"blockId": null,
"unitId": null,
"createdAt": "2014-09-17 19:54:28",
"updatedAt": "2014-09-17 19:54:28",
"residentsAccount": [5]
}]
}
GET /residentsAccount
{
"residentsAccounts": [{
"id": 5,
"email": "rocky#balboainc.me",
"admin": false,
"resident": true,
"profileId": 20,
"createdAt": "2014-09-17 19:54:29",
"updatedAt": "2014-09-17 19:54:29",
"residentsProfile": [20]
}]
}
EDIT
Besides the changes proposed by #Kingpin2k, which were spot on, i used setupcontroller in the following way:
setupController: function(controller,
controller.set('residentsAccount', models.residentsAccount);
controller.set('residentsProfile', models.residentsProfile);
}
Now everything works.
Three problems, both of your relationships should be async (since they aren't returned in the same response)
residentsAccount: DS.belongsTo('residentsAccount', {async: true})
residentsProfile: DS.belongsTo('residentsProfile', {async:true})
And both of the json response from them should be a single id, not an array
{
"residentsProfiles":[
{
"id":20,
"picture":null,
"phone":null,
"firstName":"Rocky",
"lastName":"Balboa",
"blockId":null,
"unitId":null,
"createdAt":"2014-09-17 19:54:28",
"updatedAt":"2014-09-17 19:54:28",
"residentsAccount": 5
}
]
}
Lastly, I'm not sure what you're trying to accomplish with this.profileId here, but it probably isn't doing what you think it is. this in that scope is probably the window, meaning you're passing in undefined likely.
With ember data relationship can be {async: true} or {async: false}. How to create a model FIXTURES that mimic the behavior of an synced relashionship as described in the documentation :
var attr = DS.attr,
hasMany = DS.hasMany,
belongsTo = DS.belongsTo;
App.Post = DS.Model.extend({
title: attr(),
comments: hasMany('comment'),
user: belongsTo('user')
});
App.Comment = DS.Model.extend({
body: attr()
});
Ember Data expects that a GET request to /posts/1 would return the JSON in the following format:
{
"post": {
"id": 1,
"title": "Rails is omakase",
"comments": ["1", "2"],
"user" : "dhh"
},
"comments": [{
"id": "1",
"body": "Rails is unagi"
}, {
"id": "2",
"body": "Omakase O_o"
}]
}
You'll want to override the find method of the adapter. Here is the current implementation of the find method in the FixtureAdapter. You can see that it simply finds the record with the given ID, then returns it. You're going to want to modify that so that it side-loads the proper records. Something like this:
var json = {};
json[type.typeKey] = requestedRecord;
type.eachRelationship(function(name, meta) {
if (!meta.async) {
json[meta.type.typeKey.pluralize()] = [ /* put related records here */ ];
}
});
The syntax may not be perfect, but you should get the idea.