I'm quite new to ember and trying to write a computed property that checks whether or not a user is online based on their 'state' property, defined in the user model, and then returns a count of the number of users online. This is what I have been attempting, which is not working-
onlineUsers: function() {
return this.get("model").filterBy("state", "online").get("model.length");
}.property("'model.[]'"),
And this is my user model-
App.User = DS.Model.extend({
name : DS.attr('string'),
email : DS.attr('string'),
state : DS.attr('string'),
subjects : DS.hasMany('subject')
});
Can anyone point out what I'm doing wrong?
You need to use model.#each.state
onlineUsers: function() {
return this.get("model").filterBy("state", "online").get("length");
}.property("model.#each.state"),
Also model.length in the end not work, because the result of the filterBy is a new array, and you want the length of that array.
Related
i have two models:
User:
export default DS.Model.extend({
books: hasMany('book', { async: true }),
});
book:
export default DS.Model.extend({
title: DS.attr('string'),
state: DS.attr('number'),
});
in my of my controller i am getting one user as my model and i want to create a computed property like this
activeBooks: Ember.computed('model.books', function() {
var books = this.get('model.books').filter(function (book, index, array) {
// debugger;
return (this.get('book.state') === 1);
}.bind(this));
return books;
}),
but the filter is not working and basically return a empty array.
P.S 1. i am side loading books alone with user. and at the debugger line i query for this.get('user.books.length') i get the correct number of books for each user. could someone point out what i am doing wrong here?
thanks a lot!
You can use filterBy and return the result.
activeBooks:Ember.computed('model.books', function() {
return this.get('model.books').filterBy('state',1);
})
You don't need to use bind(this) inside filter function.
I have 3 different fixture models, as shown below.
var Room = DS.Model.extend({
title: DS.attr('string'),
categories: DS.hasMany('Category', { async: true }),
isSelected: DS.attr('boolean')
});
var Category = DS.Model.extend({
title: DS.attr('string'),
room: DS.belongsTo('Room', {async: true }),
materials: DS.hasMany('Material', { async: true }),
isSelected: DS.attr('boolean')
});
var Material = DS.Model.extend({
title: DS.attr('string'),
category: DS.belongsTo('Category', {async: true} ),
isSelected: DS.attr('boolean')
});
I find when I try to view the contents inside the Materials model it is blank. In my controller I expose the materials by doing this:
currentMaterials: function() {
var room = this.filterBy('isSelected', true).get('firstObject');
var categories = room.get('categories');
var selectedCategory = categories.get('firstObject');
var material = selectedCategory.get('materials');
return material;
}.property('#each.isSelected')
However when I try to access currentMaterials the value is null. I am ONLY able to access its values if I first access the Rooms/Categories using a {{#each} loop. Oddly once I do the {{#each}} I am then able to access the values in currentMaterials.
Does anyone understand why?
It's due to fact of promises existance. Your categories relationship is async, which means that it's not present initially and ember-data should fetch it if needed. However, it takes time to fetch data, therefore ember-data returns a promise from this: var categories = room.get('categories'). After that promise, you first get firstObject from it, which does not exist for a promise (is null), and than you get materials relationship from that null. It simply is null.
However, ember templates are smart and if you put an each on them, they know that these relationships are needed and makes ember-data fetch these data.
What you can do? If you need this data to perform page-specific job, you should make sure that you have access to it before showing the page to the user - therefore in the model hook. You can use Ember.RSVP to make multiple fetch calls and set them up in the controller:
model: function() {
data =
room: store.find("room")
categories: store.find("category)
materials: store.find("material")
return Ember.RSVP.hash(data)
}
However, take notice that it will fetch all the materials, etc. If you need only the ones connected to your model, you should consider speeding up your data fetching using side loading. If you are using fixtures, it won't work.
Last that I can think of is making computed property a method that would fetch the data, but set them on other variable. You can use some kind of flag to inform the app when the data is ready:
currentMaterials: function() {
var room = this.filterBy('isSelected', true).get('firstObject');
room.get('categories').then(function(categories) {
return categories.get('firstObject').get('materials');
}).then(function(materials) {
// here you have your materials
// you can pass _this to that method and set these materials
// on some kind of controller property (e.g. materialsChosen)
// and use a flag like setting 'is Fetching' on the start of this
// computed property and setting down right here
});
}.property('#each.isSelected')
I have a hasMany relationship that I'd like to select a single member from based on a member's property value.
The example is a certificate has multiple issuances and I would like to get the most recent based on the start property. But even when I try to return just the first item in the association I can't get anything to show in the template.
App.IssuanceModel = DS.Model.extend({
start: DS.attr(),
end: DS.attr()
});
App.CertificateModel = DS.Model.extend({
issuances: hasMany('issuance', {async: true}),
currentIssuance: function(){
this.get('issuances').then(function(issuances){
return issuances.objectAt(0);
});
}.property('issuances.#each.start')
});
And in the certificate template
{{currentIssuance.start}}
I get nothing.
your return is happening asynchronously so it's really returning undefined since you don't return anything. Just use firstObject.
{{issuances.firstObject.start}}
#Kingpin2k's answer sent me down the right path. I can use the firstObject property on a sorted array of issuances, so instead of trying to calculate the currentIssuance I can sort:
sortedIssuances: function(){
return this.get('issuances').sortBy('start');
}.property('issuances.#each.start'),
And in the template just get the first object.
{{sortedIssuances.firstObject.start}}
I am trying to create a belongsTo relation, but i am always getting the following error:
Error while loading route: Error: Assertion Failed: You must include
an id in a hash passed to push
My model definition looks like this:
GambifyApp.Bet = DS.Model.extend({
scoreT1: DS.attr('string'),
scoreT2: DS.attr('string'),
user: DS.belongsTo('user')
});
Within my Json return I have simply
{
id:128433,
user:8926,
points:0,
game:94,
scoreT1:2,
scoreT2:2
}
The user value under user is my user id. Regarding Documentation(http://emberjs.com/guides/models/the-rest-adapter/#toc_relationships) it should look exactly like this. But its causing me this error. If I change my "user" property to an attribute everything is working fine.
Update:
Found the problem in my serializer that is extracting all relations and adds them as sideloaded models. Of course it was not handling the case where this relation is only an id instread of the whole object.
If you aren't including the data associated with user the relationship should be async.
GambifyApp.Bet = DS.Model.extend({
scoreT1: DS.attr('string'),
scoreT2: DS.attr('string'),
user: DS.belongsTo('user', {async:true})
});
I am experiencing a weird issue while using ember data. With the following user model everything works great.
App.User= DS.Model.extend({
firstName: attr(),
lastName: attr()
});
I call user.save() and is posts to /users with the correct data. However when i try and use a user model that has relationships on it
App.User= DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
friends: DS.hasMany('user'),
followers: DS.hasMany('user'),
});
For some reason with that model when i call user.save() it posts to /Users (note the capitalization. Also, in the response it expects it formatted {"User": {...}} instead of {"user": {...}}
Anyone run into this before? I could always add the additional endpoints to my api however I would like it to work uniform if possible.
I did a little more digging and it seems when you add a relationship to the model there is a computed property called relationshipsByName. This property, in my example, will set the meta.type property to 'User'. It works without relationships because I called the createRecord method with 'user' so i assume it uses this as the type. When the relationship is added it uses 'User'
I found that modelFor calls the resolvers normalize on the keys. So the solution is to add a custom resolver like below.
App = Ember.Application.create({
Resolver: Ember.DefaultResolver.extend({
normalize: function(fullName) {
var n = this._super(fullName);
if(fullName.startsWith('model')){
n = n.replaceAt(6, n[6].toLowerCase());
}
return n;
}
})
});
*note i have string extensions for startsWith and replaceAt