I need to perform nested grouping on my model in order to display it.
Here is the desired output I need:
---- Today ----
-- Thread 1
- Activity 1
- Activity 2
-- Thread 2
-- Activity 1
---- Yesterday ----
-- Thread 1
- Activity 1
- Activity 2
-- Thread 2
- Activity 1
I am not able to figure out an optimal way to achieve this. I need help developing a proper controller and view / template.
Here is my bare-minimum app setup with fixtures so that you have more idea about my models.
(function($, Ember) {
'use strict';
var App = Ember.Application.create({
rootElement: '#app-container'
});
App.Store = DS.Store.extend({
revision: 13,
adapter: DS.FixtureAdapter
});
App.Thread = DS.Model.extend({
title: DS.attr('string'),
url: DS.attr('string'),
kind: DS.attr('string'),
lastActivityOn: DS.attr('date'),
activities: DS.hasMany('activity')
});
App.Activity = DS.Model.extend({
kind: DS.attr('string'),
date: DS.attr('date'),
performer: DS.belongdTo('user'),
thread: DS.belongsTo('thread')
});
App.User = DS.Model.extend({
userName: DS.attr('string'),
displayName: DS.attr('string'),
profilePicUrl: DS.attr('string'),
activities: DS.hasMany('activity')
});
App.Thread.FIXTURES = [
{
id: '958173B3-EA1C-4E06-873A-038097A65E2F',
title: 'SE01',
url: '/sites/moon551/se01',
kind: 'Workspace',
lastActivityOn: '2014-03-01 10:46:31.4000000'
},
{
id: '9B45E3F0-13FD-48BE-83ED-F3C096C3BCC2',
title: 'To Do',
url: '/sites/moon551/se02/lists/todo',
kind: 'List',
lastActivityOn: '2014-02-28 11:46:31.4000000'
},
{
id: '6E6E4EE4-5568-49B3-B9E2-66CD60BA6CAC',
title: 'Design UX',
url: '/sites/moon551/se03/lists/todo/1',
kind: 'ListItem',
lastActivityOn: '2014-02-27 12:46:31.4000000'
}
];
App.Activity.FIXTURES = [
{
id: '37D7CBCD-0299-4203-8BF0-1B2DB676467F',
kind: 'Created',
date: '2014-03-01 10:30:31.4000000',
performer: 1073741823,
thread: '958173B3-EA1C-4E06-873A-038097A65E2F'
},
{
id: 'C378CD09-388C-403C-8558-3A1D6B5DCD97',
kind: 'Updated',
date: '2014-03-01 10:46:31.4000000',
performer: 1073741823,
thread: '958173B3-EA1C-4E06-873A-038097A65E2F'
},
{
id: 'C6B68036-7543-466F-85AF-141DB4874F75',
kind: 'Created',
date: '2014-02-28 11:30:31.4000000',
performer: 1073741823,
thread: '9B45E3F0-13FD-48BE-83ED-F3C096C3BCC2'
},
{
id: 'C378CD09-388C-403C-8558-3A1D6B5DCD97',
kind: 'Updated',
date: '2014-02-28 11:46:31.4000000',
performer: 1073741823,
thread: '9B45E3F0-13FD-48BE-83ED-F3C096C3BCC2'
},
{
id: 'C064010D-2603-4E28-9DE5-568212F1EFCA',
kind: 'Created',
date: '2014-02-27 12:30:31.4000000',
performer: 1073741823,
thread: '6E6E4EE4-5568-49B3-B9E2-66CD60BA6CAC'
},
{
id: '3C449D67-F231-4DB1-8D4D-AE0C39DB4E5D',
kind: 'Updated',
date: '2014-02-27 12:46:31.4000000',
performer: 1073741823,
thread: '6E6E4EE4-5568-49B3-B9E2-66CD60BA6CAC'
}
];
App.User.FIXTURES = [
{
id: 1073741823,
userName: 'Administrator',
displayName: 'System Account'
}
];
App.IndexController = Ember.ArrayController.extend();
App.IndexRoute = Ember.Route.extend({
model: function() {
return this.store.find('activity');
}
});
})(jQuery, Ember);
Here is an actual mock-up:
I'm an emberjs noob so take this answer for what it is. I was in a similar situation where I needed to group posts by dates (Year,Month,Day). I used moment.js to extract the days. Here is how I did it.
I was getting data from the server that looked like this :
{
"idea": [{
"_id": "548c7362b9b39b8305000001",
"newTitle": null,
"body": "test",
"date": "2014-12-13T17:12:02.415Z"
}, {
"_id": "548c785c94e310a905000001",
"newTitle": null,
"body": "this is my awesome idea\n",
"date": "2014-12-13T17:33:16.316Z"
}, {
"_id": "548c786e94e310a905000002",
"newTitle": null,
"body": "this is my awesome \n\nanother awesome idea\n",
"date": "2014-12-13T17:33:34.214Z"
}, {
"_id": "548cafb494e310a905000003",
"newTitle": null,
"body": "mii\n",
"date": "2014-12-13T21:29:24.934Z"
}]
}
My Emberjs Route looked like this
saveIdea.IdeasRoute = Ember.Route.extend({
model: function () {
return this.store.find('idea',{page:1,skip:1});
}
});
And My Emberjs controller is the following. I'm using moment.js to extract and format the year, month and day of my dates.
saveIdea.IdeasController = Ember.ArrayController.extend({
test : Ember.computed('content', function() {
var results = {}
var result = [];
this.get('content').forEach(function(item){
var date = item.get('date');
var month = moment(date).format('MMMM');
var year = moment(date).format('YYYY');
var day = moment(date).format('DD');
var dayOfWeek = moment(date).format('dddd');
var time = moment(date).format('LT');
var body = item.get('body');
var groupYear = result.findBy('year',year);
if(!groupYear)
{
result.pushObject(Ember.Object.create({
year: year,
months: []
}));
}
var groupMonths = result.findBy('year',year).months.findBy('month',month);
if(!groupMonths)
{
result.findBy('year',year).months.pushObject(Ember.Object.create({
month: month,
days: []
}));
}
var groupDays = result.findBy('year',year).months.findBy('month',month).days.findBy('day',day);
if(!groupDays)
{
result.findBy('year',year).months.findBy('month',month).days.pushObject(Ember.Object.create({
day: day,
ideas: []
}));
}
result.findBy('year',year).months.findBy('month',month).days.findBy('day',day).ideas.pushObject(Ember.Object.create({
idea: body,
time: time,
dayOfWeek :dayOfWeek
}));
});
return result
})
});
Then in my view, I just looped through the contents of the computed test variable.
I'm not sure how efficient this approach is, but it works just fine for me. You can use this approach to perform your nested grouping.
Related
I have an application, with 2 models: Team and User. Each team has many users, and only 1 Team Leader. On the Index view for Teams, I want to display the list of Teams, and the name of the Team leader. I can't get the name of the team leader to be displayed. Not sure what's wrong.
User Model:
export default Model.extend({
firstName: attr(),
lastName: attr(),
team: belongsTo('team', { inverse: 'users' }),
fullName: Ember.computed('firstName', 'lastName', function() {
return `${this.get('firstName')} ${this.get('lastName')}`;
})
});
Team Model:
export default Model.extend(Validations, {
name: attr(),
shortName: attr(),
description: attr(),
teamLeader: belongsTo('user', { inverse: null }),
users: hasMany('user'),
specialisationArea: attr(),
sourceEnergyTeam: attr(),
isEnergyTeam: Ember.computed('specialisationArea', function(){
return this.get('specialisationArea') == 101;
})
});
Team Index Route:
export default Ember.Route.extend({
model() {
return this.store.findAll('team');
}
});
Team List Template:
{{#each model as |team|}}
<tr>
<td>{{team.name}}</td>
<td>{{team.shortName}}</td>
<td>{{team.description}}</td>
<td>{{team.teamLeader.fullName }}</td>
<td>{{#link-to "teams.team" team}}Details{{/link-to}}</td>
</tr>
{{/each}}
And this is the mirage configuration:
this.get('/teams', () => {
return [{
id : 11,
type: 'team',
name: 'Energy',
description: 'energy desc',
shortName: 'short',
teamLeader: 12,
users: [12],
energyTeam: true
}];
});
this.get('/teams/:team_id', () => {
return {
id: 11,
type: 'team',
name: 'energy',
description: 'energy desc',
shortName: 'eg',
teamLeader: 12,
users: [12],
energyTeam: true
};
});
this.get('/users', () => {
return [{
id: 12,
type: 'user',
firstName: 'Pedro',
lastName: 'Alonso',
team: 11
}];
});
I'm not sure what's going wrong, but in the network calls I can see that only a call to '/teams' is being triggered. Any ideas?
Thanks
I'm having trouble saving "hasMany" polymorphic records in Ember Data (1.0.0-beta.15). It looks as if Ember Data isn't setting the "type" property of the polymorphic relationship. Relationships in serialized records look like:
"roles": ["1", "2"]
When I expect them to look more like:
"roles":[{
"id": "1",
"type": "professionalRole"
}, {
"id": "2",
"type": "personalRole"
}
];
I see the following error in the console:
TypeError: Cannot read property 'typeKey' of undefined
If the records come back from the server in the expected format, all is well. The error only occurs when Ember Data creates the relationship.
I experience this using the FixtureAdapter, LocalStorageAdapter, and the RESTAdapter. I've read every piece of documentation I can find on the subject, but I cannot see my mistake.
I've created a CodePen to demonstrate the problem, but I'll also paste that code below.
window.App = Ember.Application.create();
App.ApplicationAdapter = DS.FixtureAdapter;
App.Person = DS.Model.extend({
name: DS.attr(),
roles: DS.hasMany('role')
});
App.Role = DS.Model.extend({
title: DS.attr(),
person: DS.belongsTo('person', {
polymorphic: true
})
});
App.ProfessionalRole = App.Role.extend({
rank: DS.attr()
});
App.ApplicationRoute = Ember.Route.extend({
setupController: function(controller) {
var person = this.store.createRecord('person', {
name: 'James'
});
var role = this.store.createRecord('professionalRole', {
title: 'Code Reviewer',
rank: 'Expert'
});
var promises = Ember.RSVP.hash({
person: person.save(),
role: role.save()
});
promises.catch(function() {
controller.set('initialSaveResult', 'Failure');
});
promises.then(function(resolved) {
controller.set('initialSaveResult', 'Success!');
var resolvedPerson = resolved.person;
var resolvedRole = resolved.role;
// Either/both of these break it
//resolvedRole.set('person', resolvedPerson);
resolvedPerson.get('roles').addObject(resolvedRole);
var innerPromises = Ember.RSVP.hash({
person: resolvedPerson.save(),
role: resolvedRole.save()
});
innerPromises.catch(function() {
controller.set('secondSaveResult', 'Failure');
});
innerPromises.then(function() {
controller.set('secondSaveResult', 'Success!');
});
});
}
});
App.ApplicationController = Ember.Controller.extend({
initialSaveResult: "Loading...",
secondSaveResult: "Loading..."
});
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]
}
]
here is a working jsbin: http://emberjs.jsbin.com/EnOqUxe/71/edit
What i´d like to have is there the company doesn´t need any reference to the person.
non working code
App.Company.FIXTURES = [
{ id: 1, name: 'Microsoft'},
{ id: 2, name: 'Apple'}
];
App.Person.FIXTURES = [
{ id: 1, name: 'Steve Jobs', company:2},
{ id: 2, name: 'Bill Gates', company:1},
{ id: 3, name: 'Steve Ballmer', company:1}
];
How can i achieve this?
thank you
You're practically there. You just need to fix up the models a bit:
App.Company = DS.Model.extend({
name: DS.attr('string')
});
App.Person = DS.Model.extend({
name: DS.attr('string'),
company: DS.belongsTo('company', {async:true})
});
And change your model hook, since now you link to companies through people, not people through companies.
App.IndexRoute = Ember.Route.extend({
model: function() {
return this.store.find('person');
}
});
http://emberjs.jsbin.com/EnOqUxe/72/edit
I get this assertion when run the code below:
Emptying a view in the inBuffer state is not allowed and should not
happen under normal circumstances. Most likely there is a bug in your
application. This may be due to excessive property change
notifications.
Link to demo:
http://plnkr.co/edit/s3bUw4JFrJvsL690QUMi
var App = Ember.Application.create({
Store: DS.Store.extend({
revision: 4,
adapter: DS.FixtureAdapter.create()
}),
Router: Ember.Router.extend({
root: Ember.Route.extend({
index: Ember.Route.extend({
route: "/",
connectOutlets: function(router){
var person;
person = App.Person.find(657);
person.addObserver("isLoaded", function() {
return router.get('router.applicationController').connectOutlet("things", person.get("things"));
});
}
})
})
}),
ApplicationController: Em.Controller.extend(),
ApplicationView: Em.View.extend({
template: Em.Handlebars.compile("{{outlet}}")
}),
ThingsController: Em.ArrayController.extend({
thingTypes: (function() {
return App.ThingType.find();
}).property()
}),
ThingsView: Em.View.extend({
template: Em.Handlebars.compile([
'{{#each controller.thingTypes}}',
'{{this.name}}',
'{{/each}}',
'{{#each controller.content}}',
'{{this.title}}',
'{{/each}}'].join(""))
}),
//MODELS
Person: DS.Model.extend({
things: DS.hasMany('App.Thing', {
embedded: true
})
}),
Thing: DS.Model.extend({
description: DS.attr('string'),
thingType: DS.belongsTo("App.ThingType", {
embedded: true
}),
title: (function() {
return this.get("thingType.name");
}).property("description")
}),
ThingType: DS.Model.extend({
name: DS.attr("string")
})
});
App.Person.FIXTURES = [
{
id: 657,
things: [
{
id: 1,
description: "Some text",
thing_type: {
id: 1,
name: "type 1"
}
}, {
id: 2,
description: "Some text",
thing_type: {
id: 2,
name: "type 2"
}
}
]
}
];
App.ThingType.FIXTURES = [
{
id: 1,
name: "type 1"
}, {
id: 2,
name: "type 2"
}, {
id: 3,
name: "type 3"
}
];
Why is this happening?
I was having the same error while trying to load a list of dropdown values from fixtures. What resolved it was overriding queryFixtures on the fixture adapter:
App.FixtureAdapter = DS.FixtureAdapter.extend
latency: 200
queryFixtures: (records, query, type) ->
records.filter (record) ->
for key of query
continue unless query.hasOwnProperty(key)
value = query[key]
return false if record[key] isnt value
true
I probably wouldn't have figured it out had I not set the latency first. Then the error was a bit more descriptive.
a bit late I guess... but I got it to work here:
http://plnkr.co/edit/hDCT4Qy1h5aE6GjM76qp
Didn't change the logic but where its called
I modified your router like this:
Router: Ember.Router.extend({
root: Ember.Route.extend({
index: Ember.Route.extend({
route: "/",
connectOutlets: function(router) {
var person;
router.set('router.applicationController.currentPerson', App.Person.find(657));
}
})
})
})
And created an ApplicationController:
ApplicationController: Em.Controller.extend({
currentPerson: null,
currentPersonLoaded: function() {
this.connectOutlet("things", this.get("currentPerson.things"));
}.observes("currentPerson.isLoaded"),
})
I dont know if this is the output you wished but the bug vanished!