Filter data using params in ember - ember.js

I'm developing search feature in my app. What I'm trying to do is to filter a car by brand. I have the following in my route:
import Ember from 'ember';
export default Ember.Route.extend({
actions: {
filterCars(car){
this.transitionTo('cars',{ queryParams: {brand: car}});
}
},
queryParams: {
brand: {
refreshModel: true
}
},
model(params) {
if(params['marca'] != null){
this.get('store').query('car', { filter: { brand: params['marca'] } }).then(function(cars) {
return cars;
});
} else {
return this.get('store').findAll('car');
}
}
});
When I get the brand from params, I filter only the cars with that given brand. I thought it would work, but it's not working. Any idea of what I'm doing wrong ?

What is the symptom of your problem?
I notice that your model hook has an if statement with two branches, but only one of them (the else branch) results in the function returning a value. The if branch resolves a promise, but does nothing with it.
Also: is the code you show for the cars route? You may be able to simplify this page by just changing the brand parameter. I'm not sure you need to transition to the same route at all.

Use where clause in filter
import Ember from 'ember';
export default Ember.Route.extend({
actions: {
filterCars(car){
this.transitionTo('cars',{ queryParams: {brand: car}});
}
},
queryParams:{
brand:{
refreshModel: true
}
},
model(params) {
if(params['marca'] != null){
this.get('store').query('car', { filter: { where:{brand: params['marca'] } }}).then(function(cars) {
return cars;
});
} else {
return this.get('store').findAll('car');
}
}
});

Related

How to properly use parameters in Ember query?

I have been trying to implement pagination (I've tried both ember-cli-pagination and ember-simple-pagination) for my application but I've had a lot of issues. So I decided to try custom pagination and noticed that I cannot pass parameters into my query. For instance, when visiting my api at: http://jsonplaceholder.typicode.com/posts?_start=0&_limit=10, start and limit both work properly. When calling it in my route, it seems to ignore that entirely and just give me all entries. I would appreciate all insight into what I am doing wrong or how to properly implement pagination in this case.
app/adapters/post.js
import DS from 'ember-data';
export default DS.JSONAPIAdapter.extend({
host:'https://jsonplaceholder.typicode.com',
pathForType(){
return 'posts';
}
});
app/models/post.js
import DS from 'ember-data';
const { Model } = DS;
export default Model.extend({
user:DS.belongsTo('user'),
title:DS.attr('string'),
body:DS.attr('string'),
});
app/routes/post.js
import Route from '#ember/routing/route';
import { set } from '#ember/object';
import { hash } from 'rsvp';
export default Route.extend({
model() {
return hash({
post: this.store.query('post', {
start: 0,
limit: 10
}),
user: this.store.findAll('user')
});
},
setupController(controller, model) {
this._super(...arguments);
set(controller, 'posts', model.post);
set(controller, 'users', model.user);
}
});
You need define the query params in both side Route and Controller.
app/routes/post.js
import Route from '#ember/routing/route';
import { set } from '#ember/object';
import { hash } from 'rsvp';
export default Route.extend({
queryParams = {
start: {
refreshModel: true
},
limit: {
refreshModel: true
}
},
model() {
return hash({
post: this.store.query('post', {
start: 0,
limit: 10
}),
user: this.store.findAll('user')
});
},
setupController(controller, model) {
this._super(...arguments);
set(controller, 'posts', model.post);
set(controller, 'users', model.user);
}
});
And inside app/controllers/post.js
import Controller from '#ember/controller';
export default class ArticlesController extends Controller {
queryParams = ['start', 'limit'];
start = 1;
limit = 5;
}
Ember by default does not call model when query params are changed. We tell it to do so any time start/limit changes, through refreshModel: true.

RangeError: Maximum call stack size exceeded when using ember-cli-mirage

I am having issue using ember-cli-mirage. My instance of mirage is configured to use the RESTSerializer and the EmbeddedRecordsMixin for relationships. I am able to get records with relationship without a problem, however when I save the parent record I get the following error coming from the ember-data code:
RangeError: Maximum call stack size exceeded
Weirdly enough, if I just removed the EmbeddedRecordsMixin everything works fine. Is there some restriction or special thing you need to do use the EmbeddedRecordsMixin with mirage
// models/artist.js
import DS from 'ember-data';
const { attr, hasMany, Model } = DS;
export default Model.extend({
name: attr('string'),
genre: attr('string'),
country: attr('string'),
bio: attr(),
albums: hasMany('album', {
async: false
}),
songs: hasMany('song', {
async: false
})
});
// serializers/artist.js
import DS from 'ember-data';
const { RESTSerializer } = DS;
export default RESTSerializer.extend(EmbeddedRecordsMixin, {
attrs: {
albums: {
embedded: 'always'
},
songs: {
embedded: 'always'
}
}
});
// mirage/models/artist.js
import { Model, hasMany } from 'ember-cli-mirage';
export default Model.extend({
albums: hasMany(),
songs: hasMany()
});
// mirage/factories/artist.js
import { Factory, faker } from 'ember-cli-mirage';
export default Factory.extend({
name() {
return faker.name.findName();
},
genre() {
return faker.hacker.noun();
},
country() {
return faker.address.country();
},
bio() {
return faker.lorem.sentence();
},
afterCreate(artist, server) {
server.createList('album', 3, { artist });
server.createList('song', 3, { artist });
}
});
// mirage/serializers/artist.js
import { RestSerializer } from 'ember-cli-mirage';;
export default RestSerializer.extend({
embed: true,
include: ['songs', 'albums']
});

Ember : fetch data afterwards

I get some data from my API through model in route.js. This data contains somewhere an id on its own, with no relationships or included stuff to get details. So I have to make another API request to get the object with that id.
I did it with a component (to be able to send the id argument) and it works, but I would like to know if that's the way to go and if so, if I did it right and it cannot be simplified (because it looks complex to me for such a simple task):
I call my component with {{resource-name id=evaluation.manager}}
Component template just contains {{name}}
component.js:
import Ember from 'ember';
export default Ember.Component.extend({
store: Ember.inject.service(),
_getResource(id) {
return this.get('store').findRecord('resource', id);
},
resource: Ember.computed('id', function() {
const id = this.get('id');
const proxy = Ember.ObjectProxy.extend(Ember.PromiseProxyMixin);
return proxy.create({
promise: this._getResource(id)
});
}),
name: Ember.computed('resource.isFulfilled', function() {
if (this.get('resource.isFulfilled')) {
return `${this.get('resource.lastName')} ${this.get('resource.firstName')}`;
}
else {
return "...";
}
}),
didReceiveAttrs() {
const id = this.getAttr('id');
Ember.assert('resource-name must have an "id" attribute!', !Ember.isBlank(id));
}
});

Ember .save() only saving one attribute

I am trying to create and save a model in Ember but only the first entry in my form is saving leaving the others blank.
Before saving all of the models attributes are correct. (shown with logs)
Any help greatly appreciated!
My Model is:
import DS from 'ember-data';
export default DS.Model.extend({
endpoint: DS.attr('string'),
playerVersion: DS.attr('string'),
createdAt: DS.attr('date'),
updatedAt: DS.attr('date')
});
My Route is:
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.createRecord('account');
}
});
My Controller is:
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
save: function() {
var _this = this;
var model = this.get('model');
console.log(model.get('endpoint')); //Shows correct endpoint
console.log(model.get('playerVersion')); //Shows correct playerVersion
model.save().then(function(account) {
console.log(model.get('endpoint')); //Shows correct endpoint
console.log(model.get('playerVersion')); //Shows nothing
_this.transitionToRoute('accounts.index');
});
return false;
}
}
});
UPDATE - Was some settings needed on the custom Serializer needed.
export default JsonApiSerializer.extend({
keyForAttribute: function(key) {
//return Ember.String.dasherize(key);
return Ember.String.camelize(key);
},
keyForRelationship: function(key) {
//return Ember.String.dasherize(key);
return Ember.String.camelize(key);
},
keyForSnapshot: function(snapshot) {
//return Ember.String.dasherize(snapshot.typeKey);
return Ember.String.camelize(snapshot.typeKey);
},
});

Ember: returning just one record using something other than an id

Let's say that I want to have URLs like /users/JoshSmith for maximum readability/shareability.
I set up my Router:
this.resource('user', path: '/users/:username')
And my route:
var UserRoute = Ember.Route.extend({
model: function(params) {
debugger
return this.store.find('user', { username: params.username });
}
});
But this findQuery function actually returns an array, since it's calling /users?username= instead of calling /users/:username like I would normally do.
I'm a little lost as to how I should be handling this; I'm assuming there's a convention out there, I just can't find it.
As suggested here: http://discuss.emberjs.com/t/find-by-different-property/2479
Just override serialize on your route.
var UserRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('user', { username: params.username });
},
serialize: function(model) {
return { username: model.get('username') };
}
});
This replaces the default which looks like this:
serialize: function(model) {
// this will make the URL `/posts/12`
return { post_id: model.id };
}
Source: http://emberjs.com/api/classes/Ember.Route.html#method_serialize
I had this same problem as well, findQuery always returns a record array. The way I got around this was to simply change my model hook in the router to
model: function(params) {
return this.store.find('user', { username: params.username }).then(function(users) {
return users.get('firstObject');
});
}