hasMany hell - cannot access hasMany records in a component


#1

Hey All,

I have a model with a hasMany relationship defined. There’s a template that displays data from the model, and a component on the same template that is supposed to display data from the hasMany records from the defined relationship. The user gets to this template by clicking on a {{link-to}} helper that takes the model id as an argument.

I need to do pre-processing on the records in the hasMany relationship. IOW I cannot just rely on template code to display the records - the data must be manipulated in the component and then displayed.

The problem is that I am unable to access the data from the hasMany relationship in the component when the template loads. This seems to be due to delay in loading of those records. If I display raw data from the hasMany relationship using template code, the template is able to understand that the records live behind a promise, and it waits appropriately, then displays the records after they come across the wire.

How can I properly have the component perform the same wait as the template knows how to do? I’ve tried using the afterModel() hook in the route, using a then() in the component, etc. etc. and they have all failed.

What is the proper way to do this?


#2

Have you tried doing an Ember.computed() using your model? Here, my model called is alerts - even though alerts completes loading after the page loads, these computed methods will automatically re-evaulate when alerts completes loading.

	unreadAlerts: Ember.computed.filter('alerts.@each.{readFlag}', (alert) => {
		return !alert.get('readFlag');
	}),

	unreadAlertCount: Ember.computed.alias('unreadAlerts.length'),

	hasUnreadAlerts: Ember.computed('unreadAlerts', function() {
		return this.get('unreadAlerts.length') > 0;
	}),

In fact, I’ve frequently had to deal with repeating my code when working with hasMany situations, so I created a simple “mixin” to do the grunt work. The alerts member, above, is created using the mixin from the gist below like this:


export default Ember.Controller.extend(LiveDependantListMixinFactory({
	selectAs: 'alerts', // add this member to our controller
	from:     'alert', // from this ember-data model
	where:    'user', // where alert.user ==
	equals:   'feathers.user', // ... == feathers.user (feathers is an injected service)
	sortBy:   ['datetime'] // sort by alert.datetime
}), {
// the rest of the controller here
});

Side note: Any “expert” ember users out there who would like to chime in and correct me in ANYTHING I’ve said here, please feel free! I don’t claim to be right, I only claim that this works for me! :slight_smile: Cheers!