EmberJS:如何在同一条路线上加载多个模型?

Eri*_*ric 75 javascript ember.js rsvp.js

虽然我不是Web开发的新手,但我对客户端MVC框架还是一个新手.我做了一些研究,并决定试一试EmberJS.我浏览了TodoMVC指南,这对我来说很有意义......

我已经设置了一个非常基本的应用 索引路由,两个模型和一个模板.我有一个服务器端PHP脚本运行,返回一些数据库行.

让我感到困惑的一件事是如何在同一条路线上加载多个模型.我已经阅读了一些关于使用setupController的信息,但我仍然不清楚.在我的模板中,我有两个表,我试图加载不相关的数据库行.在一个更传统的Web应用程序中,我刚刚发布了sql语句并循环遍历它们以填充行.我很难将这个概念翻译成EmberJS.

如何在同一路线上加载多个不相关数据模型?

我正在使用最新的Ember和Ember Data库.

更新

虽然第一个答案给出了处理它的方法,但第二个答案解释了何时适当,以及何时不合适的不同方法.

Kin*_*n2k 151

谨防:

您需要注意是否在模型挂钩中返回多个模型是合适的.问自己这个简单的问题:

  1. 我的路由是否使用slug基于url加载动态数据:id?即 this.resource('foo', {path: ':id'});

如果你回答是的话

不要尝试从该路径中的模型钩子加载多个模型!原因在于Ember处理链接到路线的方式.如果在链接到该路径时提供模型({{link-to 'foo' model}},transitionTo('foo', model)),它将跳过模型钩子并使用提供的模型.这可能是有问题的,因为您期望多个模型,但只交付一个模型.这是另一种选择:

setupController/中做afterModel

App.IndexRoute = Ember.Route.extend({
  model: function(params) {
    return $.getJSON('/books/' + params.id);
  },
  setupController: function(controller, model){
    this._super(controller,model);
    controller.set('model2', {bird:'is the word'});
  }
});
Run Code Online (Sandbox Code Playgroud)

示例:http://emberjs.jsbin.com/cibujahuju/1/edit

如果你需要它来阻止转换(就像模型钩子那样)从afterModel钩子返回一个promise .您需要手动跟踪该挂钩的结果并将它们连接到您的控制器.

App.IndexRoute = Ember.Route.extend({
  model: function(params) {
    return $.getJSON('/books/' + params.id);
  },
  afterModel: function(){
    var self = this;
    return $.getJSON('/authors').then(function(result){
      self.set('authors', result);
    });
  }, 
  setupController: function(controller, model){
    this._super(controller,model);
    controller.set('authors', this.get('authors'));
  }
});
Run Code Online (Sandbox Code Playgroud)

示例:http://emberjs.jsbin.com/diqotehomu/1/edit

如果你回答否

来吧,让我们从路线的模型钩子返回多个模型:

App.IndexRoute = Ember.Route.extend({
  model: function() {
    return {
           model1: ['red', 'yellow', 'blue'],
           model2: ['green', 'purple', 'white']
    };
  }
});
Run Code Online (Sandbox Code Playgroud)

示例:http://emberjs.jsbin.com/tuvozuwa/1/edit

如果它是需要等待的东西(例如对服务器的调用,某种承诺)

App.IndexRoute = Ember.Route.extend({
  model: function() {
    return Ember.RSVP.hash({
           model1: promise1,
           model2: promise2
    });
  }
});
Run Code Online (Sandbox Code Playgroud)

示例:http://emberjs.jsbin.com/xucepamezu/1/edit

在Ember Data的情况下

App.IndexRoute = Ember.Route.extend({
  var store = this.store;
  model: function() {
    return Ember.RSVP.hash({
           cats: store.find('cat'),
           dogs: store.find('dog')
    });
  }
});
Run Code Online (Sandbox Code Playgroud)

示例:http://emberjs.jsbin.com/pekohijaku/1/edit

如果一个是承诺,而另一个不是,那一切都很好,RSVP很乐意只使用这个价值

App.IndexRoute = Ember.Route.extend({
  var store = this.store;
  model: function() {
    return Ember.RSVP.hash({
           cats: store.find('cat'),
           dogs: ['pluto', 'mickey']
    });
  }
});
Run Code Online (Sandbox Code Playgroud)

示例:http://emberjs.jsbin.com/coxexubuwi/1/edit

混搭,玩得开心!

App.IndexRoute = Ember.Route.extend({
  var store = this.store;
  model: function() {
    return Ember.RSVP.hash({
           cats: store.find('cat'),
           dogs: Ember.RSVP.Promise.cast(['pluto', 'mickey']),
           weather: $.getJSON('weather')
    });
  }, 
  setupController: function(controller, model){
    this._super(controller, model);
    controller.set('favoritePuppy', model.dogs[0]);
  }
});
Run Code Online (Sandbox Code Playgroud)

示例:http://emberjs.jsbin.com/joraruxuca/1/edit

  • 您仍然可以拥有多个模型,而不会破坏您的链接.如果你有两个动态段,传入一个id(如果你是通过你的路径中的`serialize:`hook基于一个slug构建你的模型的字符串),而不是在链接中传入一个模型.仅供参考模板访问模板中的模型属性的语法是`model.model1.someProperty`或`model.puppyModel.someOtherProperty` (2认同)

Mar*_*ior 95

您可以使用Ember.RSVP.hash加载多个模型:

app/routes/index.js

import Ember from 'ember';

export default Ember.Route.extend({
  model() {
    return Ember.RSVP.hash({
      people: this.store.findAll('person'),
      companies: this.store.findAll('company')
    });
  },

  setupController(controller, model) {
    this._super(...arguments);
    Ember.set(controller, 'people', model.people);
    Ember.set(controller, 'companies', model.companies);
  }
});
Run Code Online (Sandbox Code Playgroud)

在您的模板中,您可以参考peoplecompanies获取加载的数据:

app/templates/index.js

<h2>People:</h2>
<ul>
  {{#each people as |person|}}
    <li>{{person.name}}</li>
  {{/each}}
</ul>
<h2>Companies:</h2>
<ul>
  {{#each companies as |company|}}
    <li>{{company.name}}</li>
  {{/each}}
</ul>
Run Code Online (Sandbox Code Playgroud)

这是一个Twiddle与此示例:https://ember-twiddle.com/c88ce3440ab6201b8d58

  • 如果您的路线中没有任何动态段,则此方法很好.如果你有动态段并且路由是通过`{{link-to'index'someModel}}`输入的,那么模型钩子将被完全跳过,这将破坏这个例子.更强大的方法是在`setupController`中加载任何额外的模型,它始终运行. (9认同)

Nul*_*uli 6

采用已接受的答案,并将其更新为 Ember 3.16+

app/routes/index.js

import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';

export default class IndexRoute extends Route {
  @service store;

  async model() {
    let [people, companies] = await Promise.all([
      this.store.findAll('person'),
      this.store.findAll('company'),
    ]);


    return { people, companies };
  }

}
Run Code Online (Sandbox Code Playgroud)

请注意,建议不要使用 setupController 来设置别名,因为它会混淆数据的来源以及数据如何从路由流向模板。

因此,在您的模板中,您可以执行以下操作:

<h2>People:</h2>

<ul>
  {{#each @model.people as |person|}}
    <li>{{person.name}}</li>
  {{/each}}
</ul>

<h2>Companies:</h2>

<ul>
  {{#each @model.companies as |company|}}
    <li>{{company.name}}</li>
  {{/each}}
</ul>
Run Code Online (Sandbox Code Playgroud)