Technical Article => Web => JavaScript

In EmberJS, one could pass query parameters when retrieving resources with store.query() method. But what if there is a requirement that one wants to pass query parameters when calling store.findRecord()? Or there is a requirement that one wants to pass query parameters to a relationship when calling model.get('hasManyAttribute') in a RESTful style? In this post, we will explain how these can be achieved.

In the store.query() case, one could easily pass the query parameters by passing a hash to the query method. An example looks like:

store.query('someResource', { include: 'someDependantResource', filter: someFilterHash, page: { number: pageNum, size: pageSize } }).then(function(data){ successCallback(data); }).catch(function(reason){ console.log(reason); });

The second parameter is a query parameter hash which will be composed as a query parameter string when the GET request is made to backend.

Now if one has a RESTful API which will have some API look like /api/v1/some_resources/1 and it has some special requirement to pass some query parameters at the same time, the final API request path would look like /api/v1/some_resources/1?some_parameter=some_value, then the user may not be able to call store.query() but should call store.findRecord(). In this case, there is no easy way to pass the query parameters.

In EmberJS, the RESTAdapter has some hooks which can be overridden to rewrite the URL path. Among them there is one called urlForFindRecord which can be used to rewrite the URL when findRecord() is called. Hence to pass query parameters, we could override urlForFindRecord() with below similar implementation.

export default RESTAdapter.extend({ urlForFindRecord(id, modelName, snapshot) { let url = this._super(...arguments); let query = Ember.get(snapshot, 'options.query'); if (query) { url += '?' + Ember.$.param(query); } return url; } });

The key here is the Ember.get(snapshot, 'options.query') which will pull the options.query from the model snapshot from findRecord() call. To make a findRecord() call, below code can be implemented.

store.findRecord('someResource', 1, { options: { query: { some_parameter: some_value } } }).then(function(data){ successCallback(data); }).catch(function(reason){ console.log(reason); });

When above is called, the third parameter is the hash containing the query parameters. Ember.get(snapshot, 'options.query') returns the hash

{ some_parameter: some_value }

And it will be composed to a query string some_parameter=some_value when Ember.$.param(query) is called.

Now what if one model has a hasMany relationship with some other resource and some query parameters need to be passed to the relationship call when model.get('someOtherResource') is called. Fortunately, there is also method in REST adapter which can be used to rewrite the URL. The method is called findHasMany().

export default RESTAdapter.extend({ findHasMany: function(store, snapshot, url, relationship) { if (snapshot.record.get('query')) { const id = snapshot.id, type = snapshot.modelName; url = this.urlPrefix(url, this.buildURL(type, id, null, 'findHasMany')); url += "?" + Ember.$.param(snapshot.record.get('query')); } return this.ajax(url, 'GET'); } });

In this case, the snapshot.record needs to set the query parameter and in findHasMany(), this query will be read and be used to compose the query string. In application code, the model.get() code would look like:

store.findRecord('someResource', 1).then(function(data){ data.set('query', { some_parameter: some_value }); data.get('someOtherResource').reload(); successCallback(data); }).catch(function(reason){ console.log(reason); });

The final URL would be /api/v1/some_resources/1/some_other_resources?some_parameter=some_value.

Hope these tips can help you when you want to pass query parameters in different scenarios in EmberJS.