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

虽然我对web开发并不陌生,但对于客户端MVC框架,我还是一个新手。 我做了一些研究,并决定与EmberJS合作。 我经历了TodoMVC指南,这对我来说很有意义。

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

有一件令我非常困惑的事情是如何在同一条路线上加载多个模型。 我已经阅读了一些关于使用setupController的信息,但我仍然不清楚。 在我的模板中,我有两个表,我试图加载无关的数据库行。 在一个更传统的Web应用程序,我会刚刚发布到SQL语句,并通过他们填充行。 我很难将这个概念翻译成EmberJS。

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

我正在使用最新的Ember和Ember数据库。

更新

虽然第一个答案给出了一个处理方法,但是第二个答案解释了什么时候是合适的,以及不同的方法何时不合适。

您可以使用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); } }); 

在您的模板中,您可以引用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> 

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

谨防:

你要小心在模型钩子中返回多个模型是否合适。 问自己这个简单的问题:

  1. 我的路线是否使用slug :id加载基于url的动态数据? 即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'}); } }); 

例如: 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')); } }); 

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

如果你回答不

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

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

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

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

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

例如: 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') }); } }); 

例如: 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'] }); } }); 

例如: 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]); } }); 

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

我使用类似Marcio提供的答案,但看起来像这样:

  var products = Ember.$.ajax({ url: api + 'companies/' + id +'/products', dataType: 'jsonp', type: 'POST' }).then(function(data) { return data; }); var clients = Ember.$.ajax({ url: api + 'clients', dataType: 'jsonp', type: 'POST' }).then(function(data) { return data; }); var updates = Ember.$.ajax({ url: api + 'companies/' + id + '/updates', dataType: 'jsonp', type: 'POST' }).then(function(data) { return data; }); var promises = { products: products, clients: clients, updates: updates }; return Ember.RSVP.hash(promises).then(function(data) { return data; }); 

如果你使用Ember Data,对于不相关的模型来说就更简单了:

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

如果您只想检索model2的对象的属性,请使用DS.PromiseObject而不是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')) }); } }); 

如果您不介意修改API端点,那么在Ember Data v1.13中实现的JSON-API的最新版本支持在相同的请求中捆绑不同的资源。

就我而言,我有一个session端点。 会话涉及用户记录,而用户记录涉及到我始终希望随时加载的各种模型。 这一切都是为了满足这个要求。

根据规范的一个警告是,你返回的所有实体都应该以某种方式与被接收的主要实体连接。 我相信,在对JSON进行规范化时,只会遍历显式关系。

对于其他情况,我现在选择延迟加载其他模型,直到页面已经加载,即对于单独的数据面板或任何其他类型,所以至少页面尽可能快地呈现。 这样做有一些损失/改变与“自动”错误加载状态被考虑。