Sorting on numerical model attribute in Ember - ember.js

I've got a very basic Price model that looks like this:
App.Price = DS.Model.extend({
value: DS.attr()
});
App.Price.reopenClass({
FIXTURES: [
{ id: 1, value: 29.99 },
{ id: 2, value: 39.99 },
{ id: 3, value: 49.99 },
{ id: 4, value: 55.99 }
]
});
Here's the route that's using this model:
App.PricingRoute = Ember.Route.extend({
model: function(){
return this.store.find('price');
}
});
In the controller, I set the sorting to be based on the value attribute:
App.PricingController = Ember.ArrayController.extend({
sortProperties: ['value'],
sortAscending: true
});
Then my template (in Jade) where I want them to be display in sorted order:
{{#each price in this}}
li.price-levels__value {{price.value}}
.price-levels__remove("{{action 'delete' price.id}}")
{{/each}}
Problem is they're not sorted. Interesting fact is that if I change the type of the value attribute to strings, the sorting DOES work.
eg.
{ id: 1, value: '29.99' }
{ id: 2, value: '39.99' }
etc.
So how do I get the sorting to work on a numerical model attribute?

Related

Accessing model properties in Controller - Ember

So, I'm trying to access my model properties in controller.
Controller:
dashobards: [
{ id: 12, name: 'test' },
{ id: 17, name: 'test2' },
];
In route I have model named dashboards
return Ember.RSVP.hash({
dashboards: this.store.findAll('dashboard'),
}).then((hash) => {
return Ember.RSVP.hash({
dashboards: hash.dashboards
});
}, self);
I wanna have result in controller like this:
dashboards: [
{ id: 12, name: 'test' },
{ id: 17, name: 'test2' },
{ id: 17, name: 'test1' },
{ id: 20, name: 'test20' },
];
In controller I am trying to access this model like this:
this.dashborads = this.get(model.dashobards)
And it's not working, is there any other way of doing that?
Another update How to access complex object which we get it from server in ember data model attibute,
Created twiddle to demonstrate
define attribute with DS.attr(),
export default Model.extend({
permissions:DS.attr()
});
route file,
model(){
return this.store.findAll('dashboard');
}
Your server response should be like,
data: [{
type: 'dashboard',
id: 1,
attributes: {
permissions: {'name':'role1','desc':'description'}
}
}]
hbs file,
{{#each model as |row| }}
Name: {{row.permissions.name}} <br/>
Desc: {{row.permissions.desc}} <br />
{{/each}}
Update:
Still I am not sure about the requirement, Your twiddle should be minimalized working twiddle for better understanding..anyway I will provide my observation,
1.
model(params) {
this.set('id', params.userID);
const self = this;
return Ember.RSVP.hash({
dashboards: this.store.findAll('dashboard'),
user: this.store.findRecord('user', params.userID)
}).then((hash) => {
return Ember.RSVP.hash({
user: hash.user,
dashboards: hash.dashboards
});
}, self);
}
The above code can be simply written like
model(params) {
this.set('id', params.userID);
return Ember.RSVP.hash({
dashboards: this.store.findAll('dashboard'),
user: this.store.findRecord('user', params.userID)
});
}
Its good to always initialize array properties inside init method. refer https://guides.emberjs.com/v2.13.0/object-model/classes-and-instances/
For removing entry from array,
this.dashboard.pushObject({ 'identifier': '', 'role': '' }); try this this.get('dashboard').pushObject({ 'identifier': '', 'role': '' });.
if possible instead of plain object you can use Ember.Object like
this.get('dashboard').pushObject(Ember.Object.create({ 'identifier': '', 'role': '' }));
For removing entry.
removeDashboard(i) {
let dashboard = Ember.get(this, 'dashboard');
Ember.set(this, 'dashboard', dashboard.removeObject(dashboard[i]));
}
The above code can be written like, since i is an index
removeDashboard(i) {
this.get('dashboard').removeAt(i)
}
Just do return this.store.findAll('dashboard'); in route model hook, and dont override setupController hook, then in hbs you should be able to access model that will represent RecordArray. you can have a look at this answer for how to work with this.

HasMany Polymorphic Relationship In Ember Data

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]
}
]

EmberJS: Accessing child controller functionality in parent

This may be more of a structure question but the heading is my current issue.
I have the following basic app:
var App = Ember.Application.create();
App.ApplicationAdapter = DS.FixtureAdapter.extend();
App.Router.map(function () {
this.resource('numbers', {
path: '/'
});
this.resource('users');
});
App.UsersRoute = Ember.Route.extend({
model: function (params) {
return this.store.findAll('user');
}
});
App.NumbersRoute = Ember.Route.extend({
model: function (params) {
return this.store.findAll('number');
}
});
App.User = DS.Model.extend({
name: DS.attr('string'),
numbers: DS.hasMany('number', {
async: true
})
});
App.Number = DS.Model.extend({
value: DS.attr('number'),
user: DS.belongsTo('user')
});
App.NumbersController = Ember.ArrayController.extend({
total: function () {
var total = 0;
this.forEach(function (number) {
total += parseFloat(number.get('value'));
});
return total;
}.property()
});
App.User.FIXTURES = [{
id: 1,
name: 'Bob',
numbers: [100, 101]
}, {
id: 2,
name: 'Fred',
numbers: [102]
}];
App.Number.FIXTURES = [{
id: 100,
value: 25,
user: 1
}, {
id: 101,
value: 15,
user: 1
}, {
id: 102,
value: 60,
user: 2
}];
Working example with templates is here: http://jsfiddle.net/sweetrollAU/9DuR3/
The example shows a relationship between users and numbers. The first page is a list of all numbers in the app, their related user and a total of all numbers. The Users link shows the same content but each user should show its own subtotal for the numbers it has.
My question is basically, how can I access the NumbersController method 'total' in my UsersController? Should I be accessing this method or do I have the structure incorrect?
Thanks
In your case they are similar logic, but they ultimately come from different data sources. You can still create a Mixin that can help you share the code amongst different Ember objects.
App.AddNumberMixin = Em.Mixin.create({
sumNumbers: function(arr){
var total = 0;
arr.forEach(function (number) {
total += parseFloat(number.get('value'));
});
return total;
}
});
App.UserController = Ember.ObjectController.extend(App.AddNumberMixin, {
total: function () {
return this.sumNumbers(this.get('numbers'));
}.property('numbers.#each.value')
});
App.NumbersController = Ember.ArrayController.extend(App.AddNumberMixin, {
total: function () {
return this.sumNumbers(this);
}.property('#each.value')
});
http://jsfiddle.net/9DuR3/2/
#kingpin2k's answer seems sufficient, but here's another way to do it:
http://jsfiddle.net/9DuR3/3/
What happens here is that the numbers are rendered again, for each users, but this time with a different template. Namely the one between the {{render}} tags. The NumbersController is provided with the user.numbers collection, instead of the complete numbers collection.
Also it's important to specify on which properties the total function dependent is (.property('#each.value')).

Ember route getting empty model after successful promise

I've built a RESTAdapter to work with couchdb, and am testing it to make sure it works, and so far things seem fine, but my test route seems to be having other problems.
Sorry this is so long, I probably ought to set up a fiddle for it... I've just never done that before, but will look into it right now....
I've built the following (relevant) things:
App.Thing = DS.Model.extend({
rev: DS.attr(),
price: DS.attr()
});
App.Things<Index>Route = Ember.Route.extend({
model: function () {
return this.get('store').findAll('thing');
}
});
(I've tried ThingsRoute with and without the Index without any change)
In App.Router.map:
this.resource('things', function() {
this.route('thing', { path: ':thing_id'})
});
In App.ApplicationAdapter = DS.RESTAdapter.extend:
buildURL: function(type, id) {
id = id || '_all_docs?include_docs=true';
return this._super(type, id);
}
In App.ApplicationSerializer = DS.RESTSerializer.extend:
extractArray: function(store, type, payload, id, requestType) {
root = type.typeKey;
root = Ember.String.pluralize(root);
newJSON = {};
newJSON[root] = payload.rows.map(function(row) {
return row.doc;
});
payload = newJSON;
console.log(payload);
return this._super(store, type, payload, id, requestType);
},
normalize: function(type, hash, property) {
var json = { id: hash._id, rev: hash._rev};
delete hash._id;
delete hash._rev;
for (var prop in hash) {
json[prop] = hash[prop];
}
console.log(json);
return this._super(type, json, property);
}
And this template:
<script type="text/x-handlebars" data-template-name="things/index">
{{#each thing in things}}
{{thing.rev}}
{{thing.price}}
{{else}}
Empty.
{{/each}}
</script>
The console.logs in extractArray and normalize both show the following perfectly formatted and correct json:
Object {things: Array[3]}
Object {id: "8117701d38cf9a1112ce8ed38000064d", rev: "1-14918623fedb103cf035ff2489e0a6a1", price: 1}
Object {id: "8117701d38cf9a1112ce8ed3800006e5", rev: "1-09b1e6aa1fb391e11c90bca86daccb7a", price: 5}
Object {id: "8117701d38cf9a1112ce8ed38000144e", rev: "1-2a682bf7ce58829ad2054bb8f5fbe869", price: 4}
but when the template is rendered it simply shows Empty, and when I replace the model hook in the ThingsRoute to this:
return {things: [{id: 1, rev: 234, price: 4}, {id: 2, rev: 235, price: 3}]};
it works exactly as expected. AND when I define afterModel:
afterModel: function(things, transition) {
console.log(things);
console.log(transition);
}
It logs this:
Class {type: function, store: Class, isLoaded: true, isUpdating: false, toString: function…}
Transition {router: Router, promise: Promise, data: Object, resolvedModels: Object, providedModels: Object…}
that Class object has this:
content: Array[3]
0: Class
1: Class
2: Class
and each of THOSE Classes has an id field corresponding to my objects.
What's happening? Why isn't my route getting that model even after the Adapter seems to do it's job perfectly?
I think that your problem is because the things variable in your template, doesn't exist, try to update to model
<script type="text/x-handlebars" data-template-name="things/index">
{{#each thing in model}}
{{thing.rev}}
{{thing.price}}
{{else}}
Empty.
{{/each}}
</script>
Or if you want that variable you can create a alias in your controller:
App.ThingsIndexController = Ember.ArrayController.extend({
things: Ember.computed.alias('model')
});
You should be using find instead of findAll

Emberjs maximum call stack when displaying hasMany

I'm new to Ember and i have problem with display hasMany relation.
My Models:
App.Shop = DS.Model.extend({
name: DS.attr('string'),
openSettings: DS.hasMany('App.OpenSetting')
});
App.OpenSetting = DS.Model.extend({
title: DS.attr('string'),
data: DS.attr('string'),
shopId: DS.belongsTo('App.Shop')
});
I have mapping:
DS.RESTAdapter.map('App.Shop', {
openSettings: { key: 'openSettings' }
});
DS.RESTAdapter.map('App.OpenSetting', {
shopId: { key: 'shopId' }
});
In index.html in script i have:
{{#each model}}
{{id}} - {{name}} #
{{#each openSettings}}
{{title}}
{{/each}}
{{/each}}
But when object Shop has some relations in openSettings (openSettings:[1,2]) then i get error:
Uncaught RangeError: Maximum call stack size exceeded
What i'm doing wrong?
Fixtures:
App.Shop.FIXTURES = [
{
name: "Supermarket",
id: 2,
openSettings: [
2, 5
]
}
];
App.OpenSetting.FIXTURES = [
{
title: "monday - friday",
data: "8:00 - 24:00",
id: 2,
shopId: 2
},
{
title: "saturday",
data: "8:00 - 1:00",
id: 5,
shopId: 2
}
];
Thanks for help.
Ember throws that error when field is named "data". After change, all works fine.