How to use multiple models with a single route in

2019-01-05 07:27发布

From reading the docs, it looks like you have to (or should) assign a model to a route like so:

App.PostRoute = Ember.Route.extend({
    model: function() {
        return App.Post.find();
    }
});

What if I need to use several objects in a certain route? i.e. Posts, Comments and Users? How do I tell the route to load those?

8条回答
贪生不怕死
2楼-- · 2019-01-05 07:51

https://stackoverflow.com/a/16466427/2637573 is fine for related models. However, with recent version of Ember CLI and Ember Data, there is a simpler approach for unrelated models:

import Ember from 'ember';
import DS from 'ember-data';

export default Ember.Route.extend({
  setupController: function(controller, model) {
    this._super(controller,model);
    var model2 = DS.PromiseArray.create({
      promise: this.store.find('model2')
    });
    model2.then(function() {
      controller.set('model2', model2)
    });
  }
});

If you only want to retrieve an object's property for model2, use DS.PromiseObject instead of DS.PromiseArray:

import Ember from 'ember';
import DS from 'ember-data';

export default Ember.Route.extend({
  setupController: function(controller, model) {
    this._super(controller,model);
    var model2 = DS.PromiseObject.create({
      promise: this.store.find('model2')
    });
    model2.then(function() {
      controller.set('model2', model2.get('value'))
    });
  }
});
查看更多
Deceive 欺骗
3楼-- · 2019-01-05 07:57

Using Em.Object to encapsulate multiple models is a good way to get all data in model hook. But it can't ensure all data is prepared after view rendering.

Another choice is to use Em.RSVP.hash. It combines several promises together and return a new promise. The new promise if resolved after all the promises are resolved. And setupController is not called until the promise is resolved or rejected.

App.PostRoute = Em.Route.extend({
  model: function(params) {
    return Em.RSVP.hash({
      post:     // promise to get post
      comments: // promise to get comments,
      user:     // promise to get user
    });
  },

  setupController: function(controller, model) {
    // You can use model.post to get post, etc
    // Since the model is a plain object you can just use setProperties
    controller.setProperties(model);
  }
});

In this way you get all models before view rendering. And using Em.Object doesn't have this advantage.

Another advantage is you can combine promise and non-promise. Like this:

Em.RSVP.hash({
  post: // non-promise object
  user: // promise object
});

Check this to learn more about Em.RSVP: https://github.com/tildeio/rsvp.js


But don't use Em.Object or Em.RSVP solution if your route has dynamic segments

The main problem is link-to. If you change url by click link generated by link-to with models, the model is passed directly to that route. In this case the model hook is not called and in setupController you get the model link-to give you.

An example is like this:

The route code:

App.Router.map(function() {
  this.route('/post/:post_id');
});

App.PostRoute = Em.Route.extend({
  model: function(params) {
    return Em.RSVP.hash({
      post: App.Post.find(params.post_id),
      user: // use whatever to get user object
    });
  },

  setupController: function(controller, model) {
    // Guess what the model is in this case?
    console.log(model);
  }
});

And link-to code, the post is a model:

{{#link-to "post" post}}Some post{{/link-to}}

Things become interesting here. When you use url /post/1 to visit the page, the model hook is called, and setupController gets the plain object when promise resolved.

But if you visit the page by click link-to link, it passes post model to PostRoute and the route will ignore model hook. In this case setupController will get the post model, of course you can not get user.

So make sure you don't use them in routes with dynamic segments.

查看更多
登录 后发表回答