Reputation: 8742
With Ember Data you can do this:
App.Post = DS.Model.extend({
comments: DS.hasMany('comment', {async:true})
});
with the links
-object you return from the server or serialize payload client-side like this:
{
post:{
id: 1,
links: {
comments: 'comments'
}
}
}
Ember Data generates the following url /post/:post_id/comments
when you do post.get('comments')
But I got a lot of comments and I'd like to pass query params to it (just like a normal search in ember data): post.get('comments',{ from: '2014-01-01', to: '2014-01-07' });
Unfortunately it's not working. Is there another way?
See also my other question
Upvotes: 2
Views: 1707
Reputation: 351
I have written an addon to accomplish this: https://github.com/mdehoog/ember-data-has-many-query.
After installing and configuring, you should be able to query:
post.query('comments', { from: '2014-01-01', to: '2014-01-07' });
Upvotes: 4
Reputation: 424
I had to solve this problem. I couldn't find a clean solution and looking at Ember Data's source code I couldn't imagine something better. Perhaps this will help someone else.
Given a relationship like this and the need to pass query params to tell the API what comments need to be returned (e.g. you need to include a 'search' param or 'pageNumber' / 'pageSize' for pagination).
App.Post = DS.Model.extend({
comments: DS.hasMany('comment', {async:true})
});
I added a key 'params' to the options object of the hasMany attribute. The value tells the adapter what other model attribute contains params related to that hasMany relationship. (Note that 'object' isn't a default EmberData attribute type see this gist to add that type.)
App.Post = DS.Model.extend({
comments: DS.hasMany('comment', {async:true, params: 'comment_params'}),
comment_params: DS.attr('object'),
});
With the model modified to provide query params we need our adapter to consume the information:
App.ApplicationAdapter = DS.RESTAdapter.extend({
findHasMany: function(store, snapshot, url, relationship) {
var id = snapshot.id;
var type = snapshot.typeKey;
url = this.urlPrefix(url, this.buildURL(type, id));
if ('params' in relationship.options) {
var params = snapshot.attr(relationship.options.params);
if (params && Em.keys(params).length) {
var queryParams = [];
_.forEach(params, function (value, key) {
queryParams.push(
'%@=%@'.fmt(encodeURIComponent(key), encodeURIComponent(value))
);
});
url = url + '?' + queryParams.join('&');
}
}
return this.ajax(url, 'GET');
},
});
Now you can use actions in routes/controllers or observers in your controllers to modify the params attribute, then call get() or reload() on your hasMany attribute:
// some controller ...
// assume a template with binding to 'query'
queryDidChange: function() {
var model = this.get('model');
var params = model.getWithDefault('comment_params', {});
var value = this.get('query').trim();
if (value !== '') {
params['search'] = value;
} else {
delete params['search'];
}
model.set('comment_params', params);
// calling reload to get a new set of comments
// if comments have not been loaded yet only the 'get' is
// necessary.
model.get('comments').reload();
}.observes('query'),
Editorial: I really wish I didn't need to add all this code, but it seems that returning all records for a hasMany is the default with no out of the box way to alter that.
Edit #2: I use '_.forEach' from lodash. You could also use
Object.keys(params).forEach($same_foreach_function_as_above)
Upvotes: 1
Reputation: 47367
There are a slew of ways to accomplish this, I'm gonna list them all out then maybe decide which seems the best,
{
post:{
id: 1,
links: {
comments: 'comments?from=foo&to=bar'
}
}
}
Example: http://emberjs.jsbin.com/OxIDiVU/155/edit
App.ColorSerializer = DS.RESTSerializer.extend({
extractArray: function(store, type, payload) {
console.log(payload);
payload.colors.forEach(function(color){
color.links.items += "?foo=bar";
});
return this._super(store, type, payload);
}
});
Example: http://emberjs.jsbin.com/OxIDiVU/156/edit
App.ColorAdapter= DS.RESTAdapter.extend({
findHasMany: function(store, record, url) {
var host = Em.get(this, 'host'),
id = Em.get(record, 'id'),
type = record.constructor.typeKey;
if (host && url.charAt(0) === '/' && url.charAt(1) !== '/') {
url = host + url;
}
// check if post comments
var builtUrl = this.buildURL(type, id),
withPrefix = this.urlPrefix(url, builtUrl),
data = {from:'foo'};
return this.ajax(withPrefix, 'GET',{data:data});
},
});
Example: http://emberjs.jsbin.com/OxIDiVU/154/edit
Upvotes: 4