hasMany hell - cannot access hasMany records in a component

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?

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
});

https://gist.github.com/josiahbryan/75d8c298f0f7b9fe0085fc077564fa34

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!

1 Like