我有许多不同的应用程序级模型 - 即当前用户,当前帐户等 - 我想在渲染我的应用程序之前加载。应该如何以及在何处完成? This question/answer帮了很多忙,但它没有涉及异步方面。
以下代码完成了我想要的,但是在beforeModel
中加载模型(利用它等待解析的承诺)似乎并不正确。我是否应该在ApplicationRoute
?
App.ApplicationController = Ember.Controller.extend({
currentAccount: null
});
App.ApplicationRoute = Ember.Route.extend({
beforeModel: function () {
var self = this;
return App.Account.find(...).then(function (account) {
self.controllerFor('application').set('currentAccount', account);
});
}
});
感谢您的帮助!
答案 0 :(得分:6)
诀窍是从路线的模型方法中返回一个承诺
这将导致路由器转换到App.LoadingRoute路由,直到promise解析(可用于加载指示条/车轮等)
当promise解析时,App.LoadingRoute将被停用,并且将调用原始路径的setupController方法。
这适用于ember-data promises,JQuery的$ .ajax promises和ember-model的fetch promises。
确保在解决承诺后返回实际模型
如果承诺被拒绝,这也可以是处理错误的好地方 - 但我会将其留给其他一些问题。
至于您应该加载模型的位置 - 这取决于您的应用的使用情况
通常你会加载一个模型,其中URL表明你需要该模型 - 经验法则是URL中模型ID的指示。
如果您需要预取一些数据,这当然会改变。
现在有些代码:
App.SomeRoute = Ember.Route.extend({
model: function(params){
return App.SomeModel.fetch(params.model_id).then(function(modelData){
// it is better to return the actual model here, and not the promise itself
return App.SomeModel.find(params.model_id);
});
},
setupController: function(controller, model){
controller.set("model", model);
// do some controller setup here - can be omitted if no setup is needed
// this will run only after the promise has been resolved.
}
});
App.LoadingRoute = Ember.Route.extend({
activate: function(){
this._super();
// add some loading indication here
},
deactivate: function(){
this._super();
// remove loading indication
}
}
希望这有帮助。
答案 1 :(得分:6)
您想预先加载数据/模型以初始化您的应用程序,并感觉beforeModel不正确吗?
听起来你需要一个应用程序初始化程序!
在这种情况下你的朋友:
App.deferReadiness(); //暂停应用程序的进度,直到此调用的所有实例(即:多个初始值设定项)与以下调用的实例匹配:
App.advanceReadiness(); //认为这相当于承诺解析调用。
1)从您直接查找用户,修改提到的位置以适合您的应用设置:
Ember.Application.initializer({
name: 'loadUser',
after: 'store',
initialize: function(container, app) {
// modify this following to suit how you're determining the account
var url = 'user/' + currentAccount;
// tell the app to pause loading until advanceReadiness is declared
app.deferReadiness();
// load from JSON
Ember.$.getJSON('url').then(function(json) {
var store = container.lookup('store:main');
store.load(app.User, json);
// tell app to start progressing again
app.advanceReadiness();
});
}
});
2)通过元标记:
Ember.Application.initializer({
name: 'currentUser'
after: 'store',
initialize: function(container, app) {
app.deferReadiness();
$(function() {
// Look up an attribute in a meta tag
var store = container.lookup('store:main'),
attributes = $('meta[name="current-user"]').attr('content');
if (attributes) {
var obj = store.load(app.User, JSON.parse(attributes)),
user = App.User.find(obj.id),
controller = container.lookup('controller:currentUser').set('content', user);
container.typeInjection('controller', 'currentUser', 'controller:currentUser');
}
app.advanceReadiness();
});
}
});
3)通过会话数据:
Ember.Application.initializer({
name : 'currentUser',
after : 'session',
initialize: function(container, app) {
var controller = container.lookup('controller:currentUser');
container.typeInjection('controller', 'currentUser', 'controller:currentUser');
}
});
答案 2 :(得分:3)
我设法通过在ApplicationRoute中使用嵌套的Promises和afterModel方法来完成这项工作。
App.ApplicationRoute = Ember.Route.extend({
model: function() {
// load the reservation (a globally needed model)
return App.Reservation.fetch().then(function(reservations) {
return reservations.get('firstObject');
});
},
afterModel: function() {
// Load all other globally needed models
var self = this;
return App.Gender.fetch().then(function(genders) {
self.controllerFor('application').set('genders', genders);
return App.FilterAttribute.fetch().then(function(filterAttributes) {
self.controllerFor('application').set('filterAttributes', filterAttributes);
//return App.SomeOtherModel...
});
});
},
setupController: function(controller, model) {
controller.set('reservation', model);
}
});
完美地工作:-)应用程序保留在LoadingRoute中,直到加载所有记录。 请注意,我使用的是Ember Model,但这应该没有区别,只需要返回一个Promise。