Correct usage of store.loadMany() function - ember.js

I'm trying to figure out how to populate a table from a JSON object.
My JSON is a structurated object:
{
id: 0,
list: [{ username:'user_1',online:true, user:0 },
{ username:'user_2',online:true, user:0 }]
}
My Model is defined as follow:
MyTalk.WUser = DS.Model.extend({
list: DS.hasMany('MyTalk.User')
});
MyTalk.User = DS.Model.extend({
username: DS.attr('string'), // primary key
online: DS.attr('boolean'),
user: DS.belongsTo('MyTalk.WUser')
});
I am using a custom Adapter for ember-data:
DS.SocketAdapter = DS.RESTAdapter.extend(MyTalk.WebSocketConnection, {
// code not relevant
}
DS.SocketAdapter.map('MyTalk.WUser', {
list: {embedded: 'always'}
});
DS.SocketAdapter.map('MyTalk.User', {
primaryKey: 'username'
});
MyTalk.Store = DS.Store.extend({
revision: 12,
adapter: DS.SocketAdapter.create({})
});
Now I would load my data. I run in Chrome command line the following statements:
var store = DS.get('defaultStore');
var obj = {
id: 0,
list: [{ username:'user_1',online:true, user:0 },
{ username:'user_2',online:true, user:0 }]
};
var store.loadMany(MyTalk.WUser,obj);
var record = MyTalk.WUser.find(0);
record.serialize();
But it returns no record:
> Object {list: Array[0]}
thanks in advance!!

If you want to allow the adapter to deserialize embedded records (or perform any custom deserialization, for that matter), you'll need to load your data through the adapter rather than directly into the store.
var store = DS.get('defaultStore'),
obj = {
id: 0,
list: [{ username:'user_1', online:true, user:0 },
{ username:'user_2', online:true, user:0 }]
},
type = MyTalk.WUser,
adapter = store.adapterForType(type);
adapter.load(store, type, obj);

Related

Accessing model properties in Controller - Ember

So, I'm trying to access my model properties in controller.
Controller:
dashobards: [
{ id: 12, name: 'test' },
{ id: 17, name: 'test2' },
];
In route I have model named dashboards
return Ember.RSVP.hash({
dashboards: this.store.findAll('dashboard'),
}).then((hash) => {
return Ember.RSVP.hash({
dashboards: hash.dashboards
});
}, self);
I wanna have result in controller like this:
dashboards: [
{ id: 12, name: 'test' },
{ id: 17, name: 'test2' },
{ id: 17, name: 'test1' },
{ id: 20, name: 'test20' },
];
In controller I am trying to access this model like this:
this.dashborads = this.get(model.dashobards)
And it's not working, is there any other way of doing that?
Another update How to access complex object which we get it from server in ember data model attibute,
Created twiddle to demonstrate
define attribute with DS.attr(),
export default Model.extend({
permissions:DS.attr()
});
route file,
model(){
return this.store.findAll('dashboard');
}
Your server response should be like,
data: [{
type: 'dashboard',
id: 1,
attributes: {
permissions: {'name':'role1','desc':'description'}
}
}]
hbs file,
{{#each model as |row| }}
Name: {{row.permissions.name}} <br/>
Desc: {{row.permissions.desc}} <br />
{{/each}}
Update:
Still I am not sure about the requirement, Your twiddle should be minimalized working twiddle for better understanding..anyway I will provide my observation,
1.
model(params) {
this.set('id', params.userID);
const self = this;
return Ember.RSVP.hash({
dashboards: this.store.findAll('dashboard'),
user: this.store.findRecord('user', params.userID)
}).then((hash) => {
return Ember.RSVP.hash({
user: hash.user,
dashboards: hash.dashboards
});
}, self);
}
The above code can be simply written like
model(params) {
this.set('id', params.userID);
return Ember.RSVP.hash({
dashboards: this.store.findAll('dashboard'),
user: this.store.findRecord('user', params.userID)
});
}
Its good to always initialize array properties inside init method. refer https://guides.emberjs.com/v2.13.0/object-model/classes-and-instances/
For removing entry from array,
this.dashboard.pushObject({ 'identifier': '', 'role': '' }); try this this.get('dashboard').pushObject({ 'identifier': '', 'role': '' });.
if possible instead of plain object you can use Ember.Object like
this.get('dashboard').pushObject(Ember.Object.create({ 'identifier': '', 'role': '' }));
For removing entry.
removeDashboard(i) {
let dashboard = Ember.get(this, 'dashboard');
Ember.set(this, 'dashboard', dashboard.removeObject(dashboard[i]));
}
The above code can be written like, since i is an index
removeDashboard(i) {
this.get('dashboard').removeAt(i)
}
Just do return this.store.findAll('dashboard'); in route model hook, and dont override setupController hook, then in hbs you should be able to access model that will represent RecordArray. you can have a look at this answer for how to work with this.

Ember Data: saving polymorphic relationships

I'm having trouble saving "hasMany" polymorphic records in Ember Data (1.0.0-beta.15). It looks as if Ember Data isn't setting the "type" property of the polymorphic relationship. Relationships in serialized records look like:
"roles": ["1", "2"]
When I expect them to look more like:
"roles":[{
"id": "1",
"type": "professionalRole"
}, {
"id": "2",
"type": "personalRole"
}
];
I see the following error in the console:
TypeError: Cannot read property 'typeKey' of undefined
If the records come back from the server in the expected format, all is well. The error only occurs when Ember Data creates the relationship.
I experience this using the FixtureAdapter, LocalStorageAdapter, and the RESTAdapter. I've read every piece of documentation I can find on the subject, but I cannot see my mistake.
I've created a CodePen to demonstrate the problem, but I'll also paste that code below.
window.App = Ember.Application.create();
App.ApplicationAdapter = DS.FixtureAdapter;
App.Person = DS.Model.extend({
name: DS.attr(),
roles: DS.hasMany('role')
});
App.Role = DS.Model.extend({
title: DS.attr(),
person: DS.belongsTo('person', {
polymorphic: true
})
});
App.ProfessionalRole = App.Role.extend({
rank: DS.attr()
});
App.ApplicationRoute = Ember.Route.extend({
setupController: function(controller) {
var person = this.store.createRecord('person', {
name: 'James'
});
var role = this.store.createRecord('professionalRole', {
title: 'Code Reviewer',
rank: 'Expert'
});
var promises = Ember.RSVP.hash({
person: person.save(),
role: role.save()
});
promises.catch(function() {
controller.set('initialSaveResult', 'Failure');
});
promises.then(function(resolved) {
controller.set('initialSaveResult', 'Success!');
var resolvedPerson = resolved.person;
var resolvedRole = resolved.role;
// Either/both of these break it
//resolvedRole.set('person', resolvedPerson);
resolvedPerson.get('roles').addObject(resolvedRole);
var innerPromises = Ember.RSVP.hash({
person: resolvedPerson.save(),
role: resolvedRole.save()
});
innerPromises.catch(function() {
controller.set('secondSaveResult', 'Failure');
});
innerPromises.then(function() {
controller.set('secondSaveResult', 'Success!');
});
});
}
});
App.ApplicationController = Ember.Controller.extend({
initialSaveResult: "Loading...",
secondSaveResult: "Loading..."
});

HasMany Polymorphic Relationship In Ember Data

I'm really struggling to understand how polymorphic relationships worm in Ember Data (Beta 11) and cannot find any update information on how to set them up and what is expected in the JSON payload. I'm trying to create a feed of items (think facebook feed) where you have different types of items in the feed. My modeling looks something like the following.
App.Feedable = DS.Model.extend({
activities: DS.hasMany('activity')
});
App.Activity = DS.Model.extend({
feedable: DS.belongsTo('feedable', { polymorphic: true, async: false })
});
App.MemberLikeShare = DS.Model.extend({
status: DS.attr('string')
});
App.PhotoShare = DS.Model.extend({
status: DS.attr('string'),
photo: DS.attr('string')
});
When I do a fetch at /activities I send back JSON that looks like the following:
{
activities: [
{
id: 1,
feedable: { id: 1, type: 'memberLikeShare' }
},
{
id: 4,
feedable: { id: 4, type: 'memberLikeShare' }
},
{
id: 5,
feedable: { id: 5, type: 'photoShare' }
}
],
member_like_shares: [
{
id: 1,
status: 'Foo'
},
{
id: 4,
status: 'Bar'
}
],
photo_shares: [
{id: 5, photo: 'example.jpg'}
]
}
When this runs I get an error like:
You can only add a 'feedable' record to this relationship Error: Assertion Failed: You can only add a 'feedable' record to this relationship
I'm assuming my relationships are wrong or I'm sending the wrong JSON?
polymorphic relationships should extend the base type.
App.Feedable = DS.Model.extend({
activities: DS.hasMany('activity')
});
App.MemberLikeShare = App.Feedable.extend({
status: DS.attr('string')
});
App.PhotoShare = App.Feedable.extend({
status: DS.attr('string'),
photo: DS.attr('string')
});
I'd also expect them to define the activities on them.
member_like_shares: [
{
id: 1,
status: 'Foo',
activites: [1,2,3,4]
},
{
id: 4,
status: 'Bar',
activites: [1,2,3,4]
}
],
photo_shares: [
{
id: 5,
photo: 'example.jpg',
activites: [1,2,3,4]
}
]

Structuring models with ember data

I've started using ember data and I'm having some issues getting started. If my json structure for ingredients is:
[
{
"name":"flax seed",
"retailer":"www.retailer.com",
"nutrient_info":[
{
"type":"vitamin A",
"amount":"50mg"
},
{
"type":"calcium",
"amount":"30mg"
}
]
},
{
"name":"soy milk",
"retailer":"www.retailer-two.com",
"nutrient_info":[
{
"type":"vitamin D",
"amount":"500mg"
},
{
"type":"niacin",
"amount":"5000mg"
}
]
},
{ other ingredients... }
]
I think this is how I would define my models:
var attr = DS.attr,
hasMany = DS.hasMany,
belongsTo = DS.belongsTo
App.Ingredients = DS.Model.extend({
// id: attr('number'), // don't include id in model?
name: attr('string'),
retailer: attr('string'),
nutrientinfo: hasMany('nutrients')
})
App.Nutrients = DS.Model.extend({
type: attr('string'),
amount: attr('string'),
ingredient: belongsTo('ingredients')
})
What should the server payload look like, and would I need to customize the REST adapter? Do I need to define the ingredient id: attr() in the model?
Any help in clarifying some of these concepts is appreciated.
Generally model definitions are singular (additionally I changed nutrientinfo to nutrient_info):
App.Ingredient = DS.Model.extend({
// id: attr('number'), // don't include id in model?
name: attr('string'),
retailer: attr('string'),
nutrient_info: hasMany('nutrient')
})
App.Nutrient = DS.Model.extend({
type: attr('string'),
amount: attr('string'),
ingredient: belongsTo('ingredient')
})
The format would need to be as follows (from the endpoint, or using a serializer)
{
// Ingredient records
ingredients:[
{
id:1,
"name":"flax seed",
"retailer":"www.retailer.com",
"nutrient_info":[1,2]
},
{
id:2,
"name":"soy milk",
"retailer":"www.retailer-two.com",
"nutrient_info":[3,4]
},
{ other ingredients... }
],
// Nutrient records
nutrients: [
{
id:1,
"type":"vitamin A",
"amount":"50mg",
ingredient:1
},
{
id:2,
"type":"calcium",
"amount":"30mg",
ingredient:1
},
{
id:3,
"type":"vitamin D",
"amount":"500mg",
ingredient:2
},
{
id:4,
"type":"niacin",
"amount":"5000mg",
ingredient:2
}
]
}
Here's an example using a serializer and your json, I've had to manually assign ids (despite this being invalid, you should send down ids, or use UUIDs), but this should give you an idea of how to use the serializer:
App.IngredientSerializer = DS.RESTSerializer.extend({
extractArray: function(store, type, payload, id, requestType) {
var ingredients = payload,
nutrientId = 0,
ingredientId = 0,
ids = [],
nutrients = [];
ingredients.forEach(function(ing) {
ing.id = ingredientId++;
var nInfo = ing.nutrient_info,
nIds = [];
nInfo.forEach(function(n){
n.id = nutrientId++;
n.ingredient = ing.id;
nIds.push(n.id);
nutrients.push(n);
});
ing.nutrient_info = nIds;
});
payload = {ingredients:ingredients, nutrients:nutrients};
return this._super(store, type, payload, id, requestType);
}
});
http://emberjs.jsbin.com/OxIDiVU/537/edit

How to use DS.Store.registerAdapter

I try to use the 'adapter per type' feature of ember-data. Not sure whether I'm doing something wrong or if it's a bug in ember-data. Basically i thought it would work like this:
Person = DS.Model.extend({
name: DS.attr('string')
});
var personAdapter = DS.Adapter.create();
DS.Store.registerAdapter(Person, personAdapter );
The store always uses the the default adapter and not the registered 'per type adapter'
I wrote a test case to show what I mean:
var get = Ember.get, set = Ember.set;
var Person, store, adapter, personAdapter;
module("DS.Store and DS.Adapter 'adapter per type' integration test", {
setup: function() {
Person = DS.Model.extend({
name: DS.attr('string')
});
adapter = DS.Adapter.create();
personAdapter = DS.Adapter.create();
DS.Store.registerAdapter(Person, personAdapter);
store = DS.Store.create({ adapter: adapter });
},
teardown: function() {
adapter.destroy();
store.destroy();
}
});
test("test function on the per type adapter", function() {
adapter.find = function(store, type, id) {
ok(false, "should call find on the registered 'per type adapter' not on the default one");
};
personAdapter.find = function(store, type, id) {
store.load(Person, {
'id': 1,
'name': "My Name"
});
};
var person = store.find(Person, 1);
equal(person.get('name'), "My Name");
});
While debugging I noticed that the "DS.Mappable._reifyMapping" mixing explicitly checks for DS.Store and stops if the "this" is a DS.Store.
This should work.
var get = Ember.get, set = Ember.set;
var Person, StoreClass, store, adapter, personAdapter;
module("DS.Store and DS.Adapter 'adapter per type' integration test", {
setup: function() {
Person = DS.Model.extend({
name: DS.attr('string')
});
adapter = DS.Adapter.create();
personAdapter = DS.Adapter.create();
StoreClass = DS.Store;
StoreClass.registerAdapter(Person, personAdapter);
store = StoreClass.create({ adapter: adapter });
},
teardown: function() {
adapter.destroy();
store.destroy();
}
});
...
The previous answers here are no longer valid (as of Ember Data 1.0.beta.1).
Per the changelog, you now use the ModelNameAdapter syntax. For example,
App.Person = DS.Model.extend({
...
});
App.CustomAdapter = DS.Adapter.create({
url: 'your/custom/url'
});
App.PersonAdapter = App.CustomAdapter;
There is a bug report for this: Per-type Adapter not respected in case of commit
Edit: removed inappropriate comment.