I am trying iterate json response which more likely mentioned below and I want achieve this model through reflexive relation.
{
folders : [
{
id : 1,
folders [ { id : 1, folders : [] } ]
},
{
id : 2,
folders : [{ id : 1, folders : [ {id:1 , folders : [] }] }]
}
]
}
I here is my try
children: DS.hasMany('folders', {inverse: 'parent'}),
parent: DS.belongsTo('folders', {inverse: 'children'})
But does't work at all . is there any example ?
I have a similar structure for nested categories modeled like this
In my models/category.js
export default DS.Model.extend({
name: DS.attr('string'),
description: DS.attr('string'),
master: DS.belongsTo('category', {inverse: null})
});
Then in my routes/products.js I define the model hook like this
model: function() {
return {
products: this.store.findAll('product'),
categories: this.store.findAll('category')
};
}
From controllers/products.js I have access to categories and their master categories like this
var categories = this.get('model').categories;
for (var i=0; i < categories.get('length'); i++) {
var master = categories.objectAt(i).get('master').get('id');
It seems that ember takes care of everything in the background somehow.
Related
i try to build a simple chat. User can select another one to talk with it. I use Ember with firebase. I've build my model like firebase example.
This is my simple model.
User Model :
import DS from "ember-data";
var user = DS.Model.extend({
name : DS.attr('string'),
messages : DS.hasMany("message", {async : true, inverse : 'owner'})
});
export default user;
Message Model :
import DS from "ember-data";
var message = DS.Model.extend({
date : DS.attr('date'),
content : DS.attr('string'),
owner : DS.belongsTo('user', {async : true}),
target: DS.belongsTo('user', {async : true})
});
export default message;
Emberfire doesn't support 'findQuery' ember-data type search, so how can i retrieve all messages that belong to a conversation? It is the right way to define my model or is there another one? In the ideal case, i would just want retrieve all message with a single request. ( from owner to target and from target to owner)
If you're sticking with the official emberfire bindings, you can set up three models:
User:
var user = DS.Model.extend({
name : DS.attr('string'),
conversations : DS.hasMany('conversation', { async: true }),
convos_users : DS.hasMany('convo_user', { embedded: true })
});
Conversation:
var conversation = DS.Model.extend({
messages : DS.hasMany('message', { embedded: true })
});
Message:
var message = DS.Model.extend({
date : DS.attr('date'),
content : DS.attr('string'),
from : DS.belongsTo('user', { async : true })
});
And then set up the embedded convos_users index:
var convos_users = DS.Model.extend({
with : DS.belongsTo('user', {async : true}),
conversation : DS.belongsTo('conversation', { async: true })
});
So the resulting schema looks something like this in firebase:
{
'users': {
'user_1': {
'name': 'Terrance',
'conversations': {
'convo_1': true
},
'convo_users': {
0: {
'with': 'user_2',
'conversation': 'convo_1'
},
...
}
},
'user_2': {
'name': 'Phillip',
'conversations': {
'convo_1': true
},
'convo_users': {
0: {
'with': 'user_1',
'conversation': 'convo_1'
},
...
}
},
...
},
'conversations': {
'convo_1': {
'messages': {
0: {
'date': 123456789,
'content': 'Hey buddy!',
'from': 'user_1'
},
1: {
'date': 123456789,
'content': 'Hey guy!',
'from': 'user_2'
},
...
}
}
}
}
This setup lets you embed messages together in a common conversation thread, so you only retrieve the messages for the conversation you want to see. The 'from' attribute in the message lets you render the user that it came from, and sort the alignment of the chat window, or whatever you're looking to do.
Finally, indexing both the list of conversations the user has ever been in, along with an index of the other user id in the conversation and that conversation's ID. This way, when user A goes to send a message to user B, you can do a computed findBy on the 'user_conversations' index. If a match exists, open the conversation with the conversation ID found, and append the messages to the conversation's embedded message array:
actions: {
sendMessage: function(msg) {
var userX = this.current_user.get('convos_users').findBy('with','user_X');
// No User
if (!userX) {
// 1. Create a new Conversation (var myRoom)
// 2. Save room id to users
// 3. Save room to your conversations model list
}
// Else
myRoom.messages.pushObject(msg);
myRoom.save();
}
}
}
Good luck!
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]
}
]
I have a CouchDB based backend. As in every document-based store, deeply nested properties are first-class citizens. That means, a nested property does not necessarily refer to an independent object. Often, a nested property is just used to structure complex objects, without implying any belongsTo or hasMany relationship. One direct consequence of this is that nested "objects" (which are not really objects) have no IDs.
Since ember-data does not directly supported nested properties, until now I have been modelling these objects using belongsTo relationships, with success. This is the data structure that I am receiving from my backend:
{
"agents": [
{
"_id": "04ef35dd-6ab9-492f-ada6-0d4f4de9610a",
"genproperties": {
"playable-url": null
},
"org_id": 11653,
"outputs": {
"exten": null,
"extension": "c4facb9d-850c-4b67-9592-b467129fa9d4",
"jumpIfBusy": null,
"jumpIfNoAnswer": null,
"nextnode": "a1e00fb9-8604-4119-8515-3a31a36c60d1",
"startnode": null
},
"properties": {
"agent_status": "online",
"allowed_portlets": [
"xxx-portlet",
"yyy-portlet",
"zzz-portlet",
"uuu-portlet",
"ppp-portlet"
],
"default_portlet": "xxx-portlet",
"email": "a.b#c.com",
"enabled_portlets": [
"xxx-portlet",
"yyy-portlet",
"zzz-portlet",
"uuu-portlet",
],
"first_name": "John",
"main-service": null,
"name": "John Ferdinand Smith",
"portlet_language": "en",
"pov-org": null,
"services": {
"associated": {}
},
"surname1": "Ferdinand",
"surname2": "Smith"
},
"type": "wav-user"
},
...
]
}
This is my adapter:
App.Adapter = DS.RESTAdapter.extend({
bulkCommit: false,
namespace: App.config.API_NAMESPACE,
url: mynamespace.apiUrl,
serializer: App.MetaRESTSerializer.create(),
ajax: function(url, type, hash) {
var ajaxPromise = this._super(url, type, hash);
if (App.config.DEBUG_ADAPTER) { console.log('>>>>> REQUESTED > %s:%s > hash=%o ajaxPromise=%o', type, url, hash, ajaxPromise); }
ajaxPromise.then(function(json){
if (App.config.DEBUG_ADAPTER) { console.log('>>>>> RECEIVED > %s:%s > %o', type, url, json); }
});
return ajaxPromise;
}
});
These are my current model definitions:
App.NodeOutputs = DS.Model.extend({
startnode : DS.attr('string'),
jumpIfBusy : DS.attr('string'),
jumpIfNoAnswer : DS.attr('string'),
nextnode : DS.attr('string'),
extension : DS.attr('string'),
exten : DS.attr('string'),
});
App.NodeMixin = Ember.Mixin.create({
nodeType : DS.attr('string'),
nodeSubtype : DS.attr('string'),
outputs : DS.belongsTo('App.NodeOutputs'),
});
App.Adapter.map('App.GenProperties', {
playableUrl : {key: 'playable-url'},
});
App.AgentProperties = App.CommonProperties.extend({
default_portlet : DS.attr('string'),
allowed_portlets : DS.attr('rawTransform'),
portlet_language : DS.attr('string'),
verified_emails : DS.attr('rawTransform'),
email : DS.attr('string'),
agent_status : DS.attr('string'),
});
App.Agent = DS.Model.extend(App.NodeMixin, {
properties : DS.belongsTo('App.AgentProperties'),
genproperties : DS.belongsTo('App.GenProperties'),
});
And these are my mappings:
App.Adapter.map('App.NodeOutputs', {
startnode : {key: 'startnode'},
jumpIfBusy : {key: 'jumpIfBusy'},
jumpIfNoAnswer : {key: 'jumpIfNoAnswer'},
nextnode : {key: 'nextnode'},
extension : {key: 'extension'},
exten : {key: 'exten'},
});
App.Adapter.map('App.Agent', {
nodeType : { key: 'type' },
nodeSubtype : { key: 'subtype' },
outputs : { embedded: 'always' },
properties : { embedded: 'always' }
genproperties : { embedded: 'always' }
});
That was working perfectly with ember-data#0.0.14. Now I am moving to ember-data#1.0.0-beta.3, and it seems the DS.RESTAdapter.map is no longer supported.
I have taken a look at these resources:
the migration guide
and the documentation (hidden on the methods tab)
also a related question
But I still have no idea how to accomplish these two simple tasks:
how to define simple key mappings, like type -> nodeType (json -> ember model)
how to specify that a belongsTo is embedded: 'always'
Question : Is there some sample code showcasing key mappings and embedded properties for the latest ember-data? Does it support embedded properties without IDs?
I have over 30 mappings to migrate, so I'd better make sure to understand what I am doing before starting with it.
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);
I'm trying to a basic app displaying a drive , its folders and files (dive hasMany folders hasMany files) ... when implemented using handlebar templates all relations loaded fine but when I created controllers and views manually I came across some issues. the reasons that I instantiated views manually are as follows. One requirement is to load a different view ( and possibly a controller) for file objects based on the attribute "type" on the file model (for example, image files should have a App.ImageFileView and videos have App.VideoFileView). also another requirement is that routs are only for drives, thus there shouldn't be a folder or a file route. the major issue that I am facing is that the folders related to the current drive are loaded fine. but when I iterate over a folder to load the related files I always get an empty set, any help is appreciated. So my question is why are files shown when using handlebars template but not when controllers and view are instantiated manually? And how can I force the relationship to be loaded?
a fiddle is located here
App = Ember.Application.create({});
// routing
App.Router.map(function() {
this.resource('drives',{path:'/'});
this.resource('drive',{path:'/:drive_id'});
});
App.DrivesRoute = Ember.Route.extend({
model: function() {
return App.Drive.find();
}
});
App.DriveRoute = Ember.Route.extend({
model: function(params) {
rval = App.Drive.find(params.drive_id);
App.set('activeDrive',rval);
return rval;
},
setupController : function(controller, model){
debugger;
var rController = App.DrivesController.create({content:model.get('folders')});
rController.populate();
}
});
// controllers
App.DrivesController = Ember.ArrayController.extend({
populate : function(){
var drives = this.content;
debugger;
drives.forEach(function(drive){
var rc = App.DriveController.create({content:drive});
rc.populate();
var rv = App.DriveView.create({controller:rc});
rv.prepare().append('#output');
});
}
})
App.DriveController = Ember.ObjectController.extend({
populate:function(){
console.log('There are '+this.content.get('files.length')+' files');
this.content.get('files').forEach(function(file){
// not reaching this point ... files.length is always 0
});
}
});
// views
App.DriveView = Ember.View.extend({
template : Ember.Handlebars.compile('{{content.name}}'),
prepare:function(){
return this;
}
});
//Models
App.Store = DS.Store.extend({
revision: 11,
adapter: DS.FixtureAdapter.create({simulateRemoteResponse: false})
});
App.Drive = DS.Model.extend({
title : DS.attr('string'),
folders : DS.hasMany('App.Folder')
});
App.Folder = DS.Model.extend({
name : DS.attr('string'),
drive : DS.belongsTo('App.Drive'),
files : DS.hasMany('App.File')
});
App.File = DS.Model.extend({
content : DS.attr('string'),
type : DS.attr('string'),
folder : DS.belongsTo('App.Folder')
});
// Fixtures
App.Drive.FIXTURES = [
{
id:1,
title : 'First Drive Title',
folders : [11,12,13]
},
{
id:2,
title: 'Second Drive Title'
},
{
id:3,
title: 'Third Drive Title'
}
];
App.Folder.FIXTURES = [
{
id:11,
name:"Docs",
files : [111,112]
},
{
id:12,
name:"Downloads"
},
{
id:13,
name:"Music"
},
];
App.File.FIXTURES = [
{
id :111,
content : 'first file content',
type : 'Text',
folder: 11
},
{
id :112,
content : 'second file content',
type : 'Image',
folder:11
},
];
hmm, i don't know much about fixtures, but could your problem be related to the fact that you have widgets : [111,112] in your App.Folder.FIXTURES instead of files : [111,112]?
also, your folders don't seem to have any drive id. i don't know if those are explicitly necessary, though.