Ember 路线未按顺序加载
Ember routes not loaded in order
我遇到一个问题,我的路线上的 [=20=](或 afterModel
)未被调用 在 应用程序控制器已设置之后.这是一个问题,因为我需要来自应用程序控制器的一些数据。
在另一条路线中,这按我的预期工作(应用程序控制器在路线之前加载)。唯一的区别是有效的是 Ember.ArrayController
而无效的是标准 Ember.Controller
。我正在使用 beforeModel
,即使没有模型,只是因为如果不满足条件,我会尝试从它过渡。
如果我将不工作的控制器更改为 Ember.ArrayController
并在路由器中进行无意义的 model
调用,那么它仍然无法工作。
我能想到的唯一其他区别是,不工作的是嵌套控制器,仅由 route
定义,而工作的控制器未嵌套,由 [=28 定义=].
Router.map(function() {
this.resource("wizard", function() {
this.resource("wizard/schools", {path: "/schools"}, function() {
this.route("new"); // This one doesn't work
});
});
...
this.resource("schools", { path: "/schools" }); // This one does work
});
知道如何确保应用程序 route/controller 在我的路由之前加载吗?
我正在尝试按照以下方式做一些事情:
beforeModel: function() {
var customerAccountPromise = this.controllerFor('application').get('customerAccount');
var self = this;
return customerAccountPromise.then(function(customerAccount) {
return self.get('store').find('school').then(function(schools) {
if (customerAccount.get('schoolLimit') <= schools.get('length')){
self.transitionTo('school', schools.get('firstObject'));
}
});
});
},
我目前 运行:
DEBUG: Ember : 1.8.1
DEBUG: Ember Data : 1.0.0-beta.12
DEBUG: Handlebars : 1.3.0
DEBUG: jQuery : 1.11.1
更新:这里是工作路线的代码:
import Ember from 'ember';
import AuthenticatedRoute from "./authenticated";
var SchoolsRoute = AuthenticatedRoute.extend({
model: function() {
return this.get('store').find('school');
},
afterModel: function(schools) {
Ember.Logger.log("SchoolsRoute - afterModel");
var customerAccountPromise = this.controllerFor('application').get('customerAccount');
var self = this;
return customerAccountPromise.then(function(customerAccount) {
if (customerAccount.get('schoolLimit') === 1){
self.transitionTo('school', schools.get('firstObject'));
}
});
},
});
导出默认学校路线;
应用程序控制器只是会话控制器的别名。
import Ember from 'ember';
var ApplicationController = Ember.Controller.extend({
needs: ['session'],
currentUser: Ember.computed.alias('controllers.session.currentUser'),
customerAccount: Ember.computed.alias('currentUser.customerAccount'),
...
});
export default ApplicationController;
应用程序的路由器非常简单:
import Ember from 'ember';
var ApplicationRoute = Ember.Route.extend({
setupController: function(controller, model) {
Ember.Logger.log("application setupController");
return this._super(controller, model);
},
...
});
export default ApplicationRoute;
AuthenticatedRoute
中的重要部分是 beforeModel
:
beforeModel: function(transition) {
Ember.Logger.log("AuthenticatedRoute - beforeModel");
if (Ember.isEmpty(this.controllerFor('session').get('token'))) {
// set notification
return this.redirectToSignIn(transition);
}
},
SessionController
中没有其他"setting up"。它只是通过 controllerFor
调用。在 init
上,它调用一个 loadUser
方法,该方法立即记录消息 "SessionController - loadUser" 然后执行 store.find
调用,当 return 时它记录一条消息关于设置用户。
并且日志显示应用程序首先得到设置:
DEBUG: -------------------------------
DEBUG: Ember : 1.8.1
DEBUG: Ember Data : 1.0.0-beta.12
DEBUG: Handlebars : 1.3.0
DEBUG: jQuery : 1.11.1
DEBUG: -------------------------------
AuthenticatedRoute - beforeModel
SessionController - loadUser
generated -> route:loading Object {fullName: "route:loading"}
application setupController
Rendering application with default view <school-app@view:toplevel::ember365> Object {fullName: "view:application"}
generated -> controller:loading Object {fullName: "controller:loading"}
Rendering loading with default view <school-app@view:default::ember386> Object {fullName: "view:loading"}
XHR finished loading: GET "http://0.0.0.0:4200/api/users?email=ryan%40ryanjm.com".
SessionController - set user
Ember Inspector Active
XHR finished loading: GET "http://0.0.0.0:4200/api/school".
SchoolsRoute - afterModel
这是会话控制器:
import Ember from 'ember';
var SessionController = Ember.Controller.extend({
// called by updateHeaders
loadUser: function() {
Ember.Logger.log("SessionController - loadUser");
if (this.get('isSignedIn') && !this.get('currentUser')){
var self = this;
this.store.find('user', { email: this.get('email') }).then(function(users) {
Ember.Logger.log("SessionController - set user");
self.set('currentUser', users.get('firstObject'));
});
}
},
// if email/token change, update the headers
updateHeaders: function() {
if (this.get('isSignedIn')){
Ember.$.ajaxSetup({
headers: {
'X-User-Email': this.get('email'),
'X-User-Token': this.get('token')
}
});
this.loadUser();
}
}.observes('email', 'token').on('init'),
hasEmail: Ember.computed.notEmpty('email'),
hasToken: Ember.computed.notEmpty('token'),
isSignedIn: Ember.computed.and('hasEmail', 'hasToken'),
});
export default SessionController;
根据 Kingpin2k 的建议,我查看了它是竞争条件的情况,这就是问题所在。
因此,我将我的 SessionController 更改为一个普通对象,然后将其注入到应用程序路由中,这样我就可以 return loadUser
函数作为 beforeModel
中的一个 promise。
在实例化或连接任何控制器之前调用所有模型挂钩(对于 url)。您的应用程序控制器似乎是为您的其中一条路线设置的,因为您已经访问了一个父路线,该路线已经实例化并连接了应用程序控制器上的模型。尝试在您认为有效的路线上刷新页面,应用程序控制器很可能不会被连接(或者您在 setupController
期间这样做,然后应用程序控制器将被连接为出色地)。
也就是说,您可能需要来自应用程序控制器上的基础模型的数据。您可以使用 modelFor
从应用程序控制器获取模型并执行您的逻辑。此外,由于您不需要客户帐户中的任何数据来获取学校信息,因此您可以同时而不是连续地进行这些调用。
beforeModel: function() {
var customerAccountPromise = this.modelFor('application').get('customerAccount'),
self = this;
return Em.RSVP.hash({
customerAccount: customerAccountPromise,
schools: this.store.find('school')
}).then(function(hash) {
if (hash.customerAccount.get('schoolLimit') <= hash.schools.get('length')){
self.transitionTo('school', hash.schools.get('firstObject'));
}
});
// also you don't have anything to catch the exception if something goes wrong here!
},
P.S。每次你点击这条路线时,你都会去从服务器获取所有学校。您可能会考虑获取所有学校一次,然后只从商店中获取所有学校,而不是每次都调用它们。但这只是一个建议,可能对您的业务逻辑没有意义。
承诺您的用户加载
var SessionController = Ember.Controller.extend({
// called by updateHeaders
loadUser: function() {
Ember.Logger.log("SessionController - loadUser");
if (this.get('isSignedIn') && !this.get('currentUser')){
var self = this;
var loadingPromise = this.store.find('user', { email: this.get('email') }).then(function(users) {
Ember.Logger.log("SessionController - set user");
self.set('currentUser', users.get('firstObject'));
});
this.set('loadingPromise', loadingPromise);
}
},
// if email/token change, update the headers
updateHeaders: function() {
if (this.get('isSignedIn')){
Ember.$.ajaxSetup({
headers: {
'X-User-Email': this.get('email'),
'X-User-Token': this.get('token')
}
});
this.loadUser();
}
}.observes('email', 'token').on('init'),
hasEmail: Ember.computed.notEmpty('email'),
hasToken: Ember.computed.notEmpty('token'),
isSignedIn: Ember.computed.and('hasEmail', 'hasToken'),
loadingPromise: Ember.RSVP.reject()
});
已验证路由
beforeModel: function(transition) {
Ember.Logger.log("AuthenticatedRoute - beforeModel");
var sessionController = this.controllerFor('session');
if (sessionController.get('hasToken')) {
// set notification
return this.redirectToSignIn(transition);
} else {
return sessionController.get('loadingPromise');
}
},
Bleh,我在写这篇文章时才意识到,您正在覆盖 AuthenticatedRoute
中实现的 beforeModel
挂钩,因此当您点击该路线时,它不会触发 beforeModel
挂钩。在其他更改之前尝试此操作,看看它是否修复了您的预期结果。
beforeModel: function(transition) {
this._super(transition)
var customerAccountPromise = this.modelFor('application').get('customerAccount'),
self = this;
return Em.RSVP.hash({
customerAccount: customerAccountPromise,
schools: this.store.find('school')
}).then(function(hash) {
if (hash.customerAccount.get('schoolLimit') <= hash.schools.get('length')){
self.transitionTo('school', hash.schools.get('firstObject'));
}
});
// also you don't have anything to catch the exception if something goes wrong here!
},
我遇到一个问题,我的路线上的 [=20=](或 afterModel
)未被调用 在 应用程序控制器已设置之后.这是一个问题,因为我需要来自应用程序控制器的一些数据。
在另一条路线中,这按我的预期工作(应用程序控制器在路线之前加载)。唯一的区别是有效的是 Ember.ArrayController
而无效的是标准 Ember.Controller
。我正在使用 beforeModel
,即使没有模型,只是因为如果不满足条件,我会尝试从它过渡。
如果我将不工作的控制器更改为 Ember.ArrayController
并在路由器中进行无意义的 model
调用,那么它仍然无法工作。
我能想到的唯一其他区别是,不工作的是嵌套控制器,仅由 route
定义,而工作的控制器未嵌套,由 [=28 定义=].
Router.map(function() {
this.resource("wizard", function() {
this.resource("wizard/schools", {path: "/schools"}, function() {
this.route("new"); // This one doesn't work
});
});
...
this.resource("schools", { path: "/schools" }); // This one does work
});
知道如何确保应用程序 route/controller 在我的路由之前加载吗?
我正在尝试按照以下方式做一些事情:
beforeModel: function() {
var customerAccountPromise = this.controllerFor('application').get('customerAccount');
var self = this;
return customerAccountPromise.then(function(customerAccount) {
return self.get('store').find('school').then(function(schools) {
if (customerAccount.get('schoolLimit') <= schools.get('length')){
self.transitionTo('school', schools.get('firstObject'));
}
});
});
},
我目前 运行:
DEBUG: Ember : 1.8.1
DEBUG: Ember Data : 1.0.0-beta.12
DEBUG: Handlebars : 1.3.0
DEBUG: jQuery : 1.11.1
更新:这里是工作路线的代码:
import Ember from 'ember';
import AuthenticatedRoute from "./authenticated";
var SchoolsRoute = AuthenticatedRoute.extend({
model: function() {
return this.get('store').find('school');
},
afterModel: function(schools) {
Ember.Logger.log("SchoolsRoute - afterModel");
var customerAccountPromise = this.controllerFor('application').get('customerAccount');
var self = this;
return customerAccountPromise.then(function(customerAccount) {
if (customerAccount.get('schoolLimit') === 1){
self.transitionTo('school', schools.get('firstObject'));
}
});
},
});
导出默认学校路线;
应用程序控制器只是会话控制器的别名。
import Ember from 'ember';
var ApplicationController = Ember.Controller.extend({
needs: ['session'],
currentUser: Ember.computed.alias('controllers.session.currentUser'),
customerAccount: Ember.computed.alias('currentUser.customerAccount'),
...
});
export default ApplicationController;
应用程序的路由器非常简单:
import Ember from 'ember';
var ApplicationRoute = Ember.Route.extend({
setupController: function(controller, model) {
Ember.Logger.log("application setupController");
return this._super(controller, model);
},
...
});
export default ApplicationRoute;
AuthenticatedRoute
中的重要部分是 beforeModel
:
beforeModel: function(transition) {
Ember.Logger.log("AuthenticatedRoute - beforeModel");
if (Ember.isEmpty(this.controllerFor('session').get('token'))) {
// set notification
return this.redirectToSignIn(transition);
}
},
SessionController
中没有其他"setting up"。它只是通过 controllerFor
调用。在 init
上,它调用一个 loadUser
方法,该方法立即记录消息 "SessionController - loadUser" 然后执行 store.find
调用,当 return 时它记录一条消息关于设置用户。
并且日志显示应用程序首先得到设置:
DEBUG: -------------------------------
DEBUG: Ember : 1.8.1
DEBUG: Ember Data : 1.0.0-beta.12
DEBUG: Handlebars : 1.3.0
DEBUG: jQuery : 1.11.1
DEBUG: -------------------------------
AuthenticatedRoute - beforeModel
SessionController - loadUser
generated -> route:loading Object {fullName: "route:loading"}
application setupController
Rendering application with default view <school-app@view:toplevel::ember365> Object {fullName: "view:application"}
generated -> controller:loading Object {fullName: "controller:loading"}
Rendering loading with default view <school-app@view:default::ember386> Object {fullName: "view:loading"}
XHR finished loading: GET "http://0.0.0.0:4200/api/users?email=ryan%40ryanjm.com".
SessionController - set user
Ember Inspector Active
XHR finished loading: GET "http://0.0.0.0:4200/api/school".
SchoolsRoute - afterModel
这是会话控制器:
import Ember from 'ember';
var SessionController = Ember.Controller.extend({
// called by updateHeaders
loadUser: function() {
Ember.Logger.log("SessionController - loadUser");
if (this.get('isSignedIn') && !this.get('currentUser')){
var self = this;
this.store.find('user', { email: this.get('email') }).then(function(users) {
Ember.Logger.log("SessionController - set user");
self.set('currentUser', users.get('firstObject'));
});
}
},
// if email/token change, update the headers
updateHeaders: function() {
if (this.get('isSignedIn')){
Ember.$.ajaxSetup({
headers: {
'X-User-Email': this.get('email'),
'X-User-Token': this.get('token')
}
});
this.loadUser();
}
}.observes('email', 'token').on('init'),
hasEmail: Ember.computed.notEmpty('email'),
hasToken: Ember.computed.notEmpty('token'),
isSignedIn: Ember.computed.and('hasEmail', 'hasToken'),
});
export default SessionController;
根据 Kingpin2k 的建议,我查看了它是竞争条件的情况,这就是问题所在。
因此,我将我的 SessionController 更改为一个普通对象,然后将其注入到应用程序路由中,这样我就可以 return loadUser
函数作为 beforeModel
中的一个 promise。
在实例化或连接任何控制器之前调用所有模型挂钩(对于 url)。您的应用程序控制器似乎是为您的其中一条路线设置的,因为您已经访问了一个父路线,该路线已经实例化并连接了应用程序控制器上的模型。尝试在您认为有效的路线上刷新页面,应用程序控制器很可能不会被连接(或者您在 setupController
期间这样做,然后应用程序控制器将被连接为出色地)。
也就是说,您可能需要来自应用程序控制器上的基础模型的数据。您可以使用 modelFor
从应用程序控制器获取模型并执行您的逻辑。此外,由于您不需要客户帐户中的任何数据来获取学校信息,因此您可以同时而不是连续地进行这些调用。
beforeModel: function() {
var customerAccountPromise = this.modelFor('application').get('customerAccount'),
self = this;
return Em.RSVP.hash({
customerAccount: customerAccountPromise,
schools: this.store.find('school')
}).then(function(hash) {
if (hash.customerAccount.get('schoolLimit') <= hash.schools.get('length')){
self.transitionTo('school', hash.schools.get('firstObject'));
}
});
// also you don't have anything to catch the exception if something goes wrong here!
},
P.S。每次你点击这条路线时,你都会去从服务器获取所有学校。您可能会考虑获取所有学校一次,然后只从商店中获取所有学校,而不是每次都调用它们。但这只是一个建议,可能对您的业务逻辑没有意义。
承诺您的用户加载
var SessionController = Ember.Controller.extend({
// called by updateHeaders
loadUser: function() {
Ember.Logger.log("SessionController - loadUser");
if (this.get('isSignedIn') && !this.get('currentUser')){
var self = this;
var loadingPromise = this.store.find('user', { email: this.get('email') }).then(function(users) {
Ember.Logger.log("SessionController - set user");
self.set('currentUser', users.get('firstObject'));
});
this.set('loadingPromise', loadingPromise);
}
},
// if email/token change, update the headers
updateHeaders: function() {
if (this.get('isSignedIn')){
Ember.$.ajaxSetup({
headers: {
'X-User-Email': this.get('email'),
'X-User-Token': this.get('token')
}
});
this.loadUser();
}
}.observes('email', 'token').on('init'),
hasEmail: Ember.computed.notEmpty('email'),
hasToken: Ember.computed.notEmpty('token'),
isSignedIn: Ember.computed.and('hasEmail', 'hasToken'),
loadingPromise: Ember.RSVP.reject()
});
已验证路由
beforeModel: function(transition) {
Ember.Logger.log("AuthenticatedRoute - beforeModel");
var sessionController = this.controllerFor('session');
if (sessionController.get('hasToken')) {
// set notification
return this.redirectToSignIn(transition);
} else {
return sessionController.get('loadingPromise');
}
},
Bleh,我在写这篇文章时才意识到,您正在覆盖 AuthenticatedRoute
中实现的 beforeModel
挂钩,因此当您点击该路线时,它不会触发 beforeModel
挂钩。在其他更改之前尝试此操作,看看它是否修复了您的预期结果。
beforeModel: function(transition) {
this._super(transition)
var customerAccountPromise = this.modelFor('application').get('customerAccount'),
self = this;
return Em.RSVP.hash({
customerAccount: customerAccountPromise,
schools: this.store.find('school')
}).then(function(hash) {
if (hash.customerAccount.get('schoolLimit') <= hash.schools.get('length')){
self.transitionTo('school', hash.schools.get('firstObject'));
}
});
// also you don't have anything to catch the exception if something goes wrong here!
},