Ember Model correct way Post and Comments Async - ember.js

I have a initial page where shows all posts.
Post as many comments, but in this initial page I don't wanna show comments. When User click in a post, the application goes to url posts/post/1 in this page I wanna show the comments of post.
My server has this endpoint
My server should provide separates endpoints for /posts and /comments or posts/:id/comments/ ?
what/how is the right way to fetch(fetch or find)?
Model
// Post
export default DS.Model.extend({
message: DS.attr('string'),
comments: DS.hasMany('comment'),
});
// Comment
export default DS.Model.extend({
message: DS.attr('string'),
post: DS.belongsTo('post'),
});

The best solution would be for your server to return the comments along with the post - called "sideloading".
So, if you called a GET on /post/1 and that post had comments 1,2, and 3, the JSON returned would include the "post" as well as those three comments

When you navigate to that URL "posts/post/1" you can get the dynamic segment value i.e 1 in your case.
In your model hook (in post route) find comment with that dynamic segment value
Eg:
model: function() {
return this.store.find("comments", post_id);
}
In your controller you can access this model by
var temp = this.get('model');

Related

override ember-data's url conventions

In my ember-app I have this model:
//models/photo.js
export default DS.Model.extend({
image: DS.attr(),
title: DS.attr('string'),
caption: DS.attr('string'),
published: DS.attr('boolean')
});
Then I have to fetch data for it from a REST api; in particular the photo model should be fecthed from 2 endpoints in this way:
route /aaa --> should fetch from /photos endpoint that returns an array of all photos;
this is easy:
var photos = this.store.findAll('photo')
and ember-data will automatically call the /photos endpoint, since this follows its conventions;
route /bbb --> should fetch from /feed; the /feed REST api endpoint returns also an array of photos (same model as above) but filtered in a certain way;
in any case the it returns an array of photos objects, like the /photos endpoint;
but in this case it is not possible to do
var photos = this.store.findAll('photos')
as in the /aaa route, since doing this will tell ember-data to fetch from /photos endopoint;
How can I fetch the same model from different endpoints in different routes?
(I use ember 2.2.0 with ember-data 2.2.1)
You can't do that unless you're doing a plain ol ajax call and push the payload to store or patch the adapter. I wouldn't recommend messing with ember data and its adapter as it will definitely come back to bite you. What you could do is pass in a parameter and change the logic in the API controller to do a if/else check on that param and send the relevant data that you need.
Route 1 - this.store.query('photo', { type: 'png' })
Route 2 - this.store.query('photo', { type: 'jpeg' })
The short answer is you can't because adapters are per model, not per route.
To get around this, however, you can use a plain ajax call paired with store.push/store.pushPayload to load the data into the store.
See the store documentation for further details.

Accessing store in another route

I have this model:
App.Game = DS.Model.extend({
name: attr(),
uri: attr()
});
and this route:
App.GamesRoute = Ember.Route.extend({
model: function() {
return this.store.find('game');
}
});
This works fine, calls the backend server, and stores elements in the store (I've checked with Ember inspector). This is the json I return:
{"games":[{"id":"TicTacToe","name":"TicTacToe","uri":"http://localhost:10000/games/TicTacToe"}]}
Now I have this template for 'games' (snipped):
{{#each game in model}}
{{#link-to 'games.matchlist' game.id}}{{game.uri}}{{/link-to}}
This shows the URI for each game. Now in the games.matchlist route what I would like to do is to search in the store by the game_id received param and get the game URI. The reason is that the server doesn't follow RESTAdapter conventions, and I would like to make a custom AJAX query to that URI myself.
This doesn't work:
App.GamesMatchlistRoute = Ember.Route.extend({model: function(params) {
var store = this.store;
var game = store.find('game', params.game_id)
console.log(game);
console.log("URI: " + game.uri);
at this point, game is an object but it's not an instance of my model. It doesn't have a uri attribute. What am I doing wrong? I'm feeling that I'm missing something obvious.
If you want to get records without hitting the server and you know you already have it in the store, use this.store.getById('game', ID).
I'm on my mobile, but you need to create a GameAdapter and customize I believe the fetch function. Checkout the docs for adapters on the ember site and you should have your answer.
Your other option is to fetch the data from your server and use this.store.pushPayload(data).
Docs here: http://emberjs.com/api/data/classes/DS.Store.html#method_pushPayload
And the adapter docs here: http://emberjs.com/guides/models/customizing-adapters/

How to use Ember Data with Nested Resources

My application backend has several resources. A model is exposed for each resource.
The entry point to all other resources is through the User model. What I mean is, given a User we can find BlogPost. Given a BlogPost we can find Comments etc.
In Ember terminology, we could say:
User hasMany BlogPost
BlogPost hasMany Comment
Comment belongsTo BlogPost
By backend exposes REST APIs of the form:
GET /api/v1/users/1
GET /api/v1/users/1/blog_posts/1
GET /api/v1/users/1/blog_posts/1/comments/1
I'm trying to figure out how to use Ember Data to fetch Comment belonging to a certain BlogPost belonging to a certain User.
From what I see, if I define a typical Ember model for Comment:
App.Comment = DS.Model.extend({
...
blogPost: DS.belongsTo('App.BlogPost')
});
and in the CommentRoute I have the following:
var CommentRoute = MessageRoute.extend({
model: function(params) {
this.store.find('comment')
},
The request is sent to:
/api/v1/comments
I don't even know where to begin in order for Ember Data to use urls of the form:
GET /api/v1/users/1/blog_posts/1/comments/1
I've seen several similar questions asked (see links below), but haven't seen a definitive answer to any of them. Most of them are almost a year old when ember-data, perhaps, did not have such functionality (or so it is claimed in some of these threads).
I ask again to confirm whether ember-data has such functionality or not.
Similar Questions:
Ember Data nested Models
Canonical way to load nested resources
Deep nested routes
The best way to handle it is with links. If you don't want to do it like that, it is far from supported, and difficult to hack in (the pipeline just doesn't easily pass the information around). Personally I'd recommend rolling your own adapter in that case (Ember without Ember Data).
App.Foo = DS.Model.extend({
name: DS.attr('string'),
bars : DS.hasMany('bar', {async:true})
});
App.Bar = DS.Model.extend({
foo: DS.belongsTo('foo'),
});
json:
{
id: 1,
name: "bill",
links: {
bars: '/foo/1/bars'
}
}
Example: http://emberjs.jsbin.com/OxIDiVU/971/edit

Dynamic segment in ember data adapter

I'm making an app that retrieves data of an API which is not in my control. I have the following scenario:
The path for retrieving the posts is /api/posts. So I configured my ApplicationAdapter as follows:
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'api'
});
The url for retrieving comments is '/api/posts/1/comments'. You can see that the url is prefixed by the path for retrieving a single post followed by the default path /comments.
Ember data defaults to /api/comments. But I want to configure an adapter for my Comment-model so it makes the correct url: /api/posts/:post_id/comments with :post_id replaced with the id of the current post. How do I do that?
Modify your post json to include the hasMany as links (this could be done clientside), when it builds up the url it will prepend the url of the post, giving you post/1/comments
App.Post = DS.Model.extend({
comments: DS.hasMany('comment', {async:true})
});
{
post:{
id: 1,
links: {
comments: 'comments'
}
}
}
Here's a dinky example with colors and items
http://emberjs.jsbin.com/OxIDiVU/68/edit

Ember children defined by a hasMany relationship suddenly change to embedded model

I have the following model defined:
App.Post = DS.Model.extend({
title: DS.attr('string'),
comments: DS.hasMany('comment')
});
App.Comment = DS.Model.extend({
message: DS.attr('string')
});
If I create a Post entry with a Comment, the JSON stored in my browsers local storage references the Comments as an array of IDs which works great:
...
"o3duh":{
"id":"o3duh",
"title":"How to write Ember",
"comments":[
"jf0a2"
]
}
...
However, the moment I add another Post, the JSON suddenly changes such that Comments are embedded:
...
"o3duh":{
"id":"o3duh",
"title":"How to write Ember",
"comments":[
{
"message":"First!"
}
]
},
"6kudl":{
"id":"6kudl",
"title":"Learning Ember is painful",
"comments":[
]
}
...
Why is this happening? Can I prevent it? This is causing me problems because once it changes into this embedded format, the data cannot be read by the LSAdapter when reloading the page.
Here is a JSBin so you can see it happen for yourself and see the full JSON etc. To reproduce the problem, just create a post and add a comment then you can refresh the page without problem. Then add another post and try to refresh the page.
I'm not sure if the problem is with ember-data or the localstorage adapter.
I solved the problem by modifying the LocalStorageAdapter so that it only attempts to persist JSON in the expected format.
You can see the pull request I submitted to the original author here: https://github.com/rpflorence/ember-localstorage-adapter/pull/26
Hopefully it will either get folded into the LSAdapter project, or better still, someone will come up with a better solution ;)
I was able to fix the JSON issue by defining the inverse relationship on Comment:
App.Comment = DS.Model.extend({
message: DS.attr('string'),
post: DS.belongsTo('post')
});
There are new issues now, but hopefully this will help.