Multiple nested models in one route


#1

I’m building a quoting tool at the moment. I’m struggling with how to load nested models with only one parent route. My quote is a document. Each document has many sections and each section has many lineItems. The caveat is that I want my route to be /documents/123, and for that route to show the document with all it’s sections and all of the lineItems. I started by making a route for document.show:

Router.map(function() {
    this.route('documents', function() {
        this.route('show', { path: ":document_id"});
    });
});

In this route I started loading the document:

export default Ember.Route.extend({
    model(params) {
        return this.get('store').findRecord('document', params.document_id);
    }
});

Then I needed to get all the sections for the document, so I did this:

export default Ember.Route.extend({
    model(params) {
        return RSVP.hash({
            document: this.get('store').findRecord('document', params.document_id),
            sections: this.get('store').findRecord('document', params.document_id).then((document) => {
                return document.get('sections');
            })
        });
    }
});

Then I needed to get all the lineItems for each section… at which point I felt like I wasn’t approaching the problem in the ‘ember’ way, as it felt really awkward.

I’ve read this article about making components load their own data: http://forspareparts.github.io/2016/01/24/actions-up-data-sideways/. It’s a solution I thought about implementing, but I don’t know if it’s a good solution?

Basically looking for advice from more experienced Ember devs on how you would handle this situation. I can’t find any resources online that cover this situation, maybe I’m looking in the wrong places.


#2

I use setupController for this.


#3

There’s a great article about it on emberigniter


#4

Hi, thanks for answers.

@Henry I’ve read that article and the solution to two levels of nesting is to have your url /posts/1/files/other. This doesn’t work for me. I have a document with multiple sections, each section has multiple line items. Users won’t want to see a url /documents/1/sections/3/line-items/23, they’re looking at the whole document.

@broerse I have not used setupController, but it isn’t really necessary in my above example because on the template the models appear anyway as {{model.document}} and {{model.sections}}. Can I ask, what if the author model had followers, so something like:

export default DS.Model.extend({
    name: DS.attr('string'),
    posts: DS.hasMany('post'),
   followers: DS.hasMany('follower')
});

Then on your posts/show route you’d want to show the post, it’s content, the author and suppose a count of the authors followers. How would you do that?

I’m thinking at the moment you’d have an author component and that get’s passed in the author and then requests the followers from the store?

I think that’s how I’d solve it. So for my example I’ll make a section component that’ll request all the the lineItems for it’s section from the store.

Unless there are any advances on why that’s not a good idea.


#5

Regardless of how you plan to design that in terms of components, it’s clear that you have to access data by traversing the model graph and NOT using setupController, RSVP.hash or anything like that.

If you want to display sections and lineIitems, then access them in the template via the model and its computed properties (#each model.sections as |section|) , once you have the section access section.lineItems

You may be asking yourself how to access that if your relationships are async. If so, read https://emberigniter.com/guide-promises-computed-properties/ and you will understand exactly how.


#6

Thanks Frank, that cleared it up!