ui-router 和登录 url return 状态
ui-router and login url return state
这是一个复杂的问题。
我正在尝试为用户尝试访问需要授权的页面时创建 returnState。
所以,我在状态 object 上创建了一些数据,如下所示:
$stateProvider.state('account', {
url: '/account',
templateUrl: '/app/account/index.tpl.html',
controller: 'AccountController',
controllerAs: 'controller',
data: {
requireLogin: true,
state: 'account' // tells the page to redirect here if not logged in
}
});
然后我在 stateChangeStart 上 运行 编写了这段代码:
.run(['$rootScope', '$state', 'AccountService', function ($rootScope, $state, account) {
// On state change
$rootScope.$on('$stateChangeStart', function (event, toState) {
var data = toState.data; // Get our state data
var requireLogin = typeof data === 'undefined' ? false : data.requireLogin; // Check to see if we have any data and if so, check to see if we need login rights
var user = account.current() // Get our current user
// If we require login rights and we are not authenticated
if (requireLogin && !user.authenticated) {
// Get our current state
var state = data.state || '';
// Stop processing
event.preventDefault();
// redirect to the login page and pass the state parameter
$state.transitionTo('login', { returnState: state });
}
});
}]);
然后在我的 loginController 上我有这个功能:
self.loginUser = function () {
// Login
self.login = service.login(self.model);
// If we login properly
self.login.promise.then(function (response) {
// If we have a return Url
if (returnState) {
// Go to that url
$state.go(returnState);
} else {
// Otherwise, Redirect to the home page
$state.go('home');
}
});
};
我展示的示例非常有效。但是现在我发现我有更复杂的需求。
我有另一组状态:
$stateProvider.state('designer', {
url: '/:sport/designer',
abstract: true,
templateUrl: '/app/designer/designer.tpl.html',
controller: 'DesignerController',
controllerAs: 'controller'
}).state('designer.team', {
url: '',
templateUrl: '/app/designer/team.tpl.html'
}).state('designer.kit', {
url: '/kit',
templateUrl: '/app/designer/kit.tpl.html'
}).state('designer.design', {
url: '/design',
templateUrl: '/app/designer/design.tpl.html'
}).state('designer.refine', {
url: '/refine',
templateUrl: '/app/designer/refine.tpl.html'
}).state('designer.order', {
url: '/order',
templateUrl: '/app/designer/order.tpl.html'
}).state('designer.save', {
url: '/save',
templateUrl: '/app/designer/save.tpl.html',
data: {
requireLogin: true
}
});
如您所见,这个状态和一些 children 以及最后一个状态(保存)要求用户登录。因为状态继承了它们的参数 parents 我应该是能够做类似的事情:
state: 'designer.save({ sport: :sport })'
但我收到一条错误消息:
Error: Could not resolve 'desginer.save({ sport: :sport })' from state 'login'
现在我假设这是因为 :sport 没有作为字符串传递,但我已经尝试过 alsorts 但我无法让它工作。
有没有更好的方法来处理路由?
我确实尝试过使用 stateChangeStart 函数来获取我们要移动的状态,但我似乎无法访问它。
首先,如果我们查看 the docs,我们可以看到 $state.go
接受以下参数:
- 绝对状态名称
- 参数
- 选项
我没有看到任何地方提到将参数直接放入状态名称是合法的。所以我们有错误消息的原因。 'designer.save({ sport: :sport })'
不是 正确的绝对州名称。
Because states inherit the parameters of their parents
这意味着您不仅可以访问它们,而且在某些情况下它们会自动通过:
Any parameters that are not specified will be inherited from currently
defined parameters. This allows, for example, going to a sibling state
that shares parameters specified in a parent state. Parameter
inheritance only works between common ancestor states, I.e.
transitioning to a sibling will get you the parameters for all
parents, transitioning to a child will get you all current parameters,
etc.
因此,只要您处于 designer
状态或其任何子状态,您就不必提供任何参数。如果你不是,那么你需要找到一种方法将参数作为第二个参数传递给 $state.go
.
感谢user2847643的建议。我实际上想出了一个更好的方法来处理这个问题。
首先,我将 login 状态修改为:
$stateProvider.state('login', {
url: '/account/login',
params: {
returnState: '',
returnParams: {}
},
views: {
// the main template will be placed here (relatively named)
'': {
templateUrl: 'app/account/login/index.tpl.html'
},
// the child views will be defined here (absolutely named)
'register@login': {
templateUrl: 'app/account/login/register.tpl.html',
controller: 'RegisterController',
controllerAs: 'controller'
},
// for column two, we'll define a separate controller
'login@login': {
templateUrl: 'app/account/login/login.tpl.html',
controller: 'LoginController',
controllerAs: 'controller'
}
}
});
如您所见,它接受两个可选参数。
然后我将登录功能修改为:
self.loginUser = function () {
// Login
self.login = service.login(self.model);
// If we login properly
self.login.promise.then(function (response) {
console.log(returnState);
console.log(returnParams);
// If we have a return Url
if (returnState) {
// Go to that url
$state.go(returnState, returnParams);
} else {
// Otherwise, Redirect to the home page
$state.go('home');
}
});
};
现在可以正确调用传递状态和参数(或空对象)的 $state.go 函数。
我实际上将处理 returnStates 的逻辑放在我之前展示的 stateChangeStart 绑定中,所以现在看起来像这样:
$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
var data = toState.data; // Get our state data
var requireLogin = typeof data === 'undefined' ? false : data.requireLogin; // Check to see if we have any data and if so, check to see if we need login rights
var user = account.current() // Get our current user
// If we require login rights and we are not authenticated
if (requireLogin && !user.authenticated) {
// Get our current state
var name = toState.name;
var params = toParams;
// If our state is the login page (i.e. we accessed it directly)
if (name === 'login') {
// Set our state to the homepage
name = 'home';
toParams = {};
}
// Stop processing
event.preventDefault();
// redirect to the login page and pass the state parameter
$state.transitionTo('login', { returnState: name, returnParams: params });
}
});
我们已经做到了。
感谢 r3plica post。我遇到的问题很少,并通过以下方式解决了。如果我错了,有人可以纠正我。
- 你应该使用ui-router最新版本,旧版本不支持params。我正在使用 0.2.13.
- 在控制器中,您需要读取参数为 $state.go($stateParams.returnState, $stateParams.returnParams)
在$stateChangeStart事件中,还需要传递参数fromState,fromParams。这是用来检查fromState是否不是登录,所以你一次又一次地跳过重新加载登录页面。
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){
// var restrictedPage = $.inArray($location.path(),['/landing', '/list','/landing/users']);
var data = toState.data;
if(typeof toState.data !== 'undefined' && fromState.name !== 'login'){......}
}
这是一个复杂的问题。 我正在尝试为用户尝试访问需要授权的页面时创建 returnState。
所以,我在状态 object 上创建了一些数据,如下所示:
$stateProvider.state('account', {
url: '/account',
templateUrl: '/app/account/index.tpl.html',
controller: 'AccountController',
controllerAs: 'controller',
data: {
requireLogin: true,
state: 'account' // tells the page to redirect here if not logged in
}
});
然后我在 stateChangeStart 上 运行 编写了这段代码:
.run(['$rootScope', '$state', 'AccountService', function ($rootScope, $state, account) {
// On state change
$rootScope.$on('$stateChangeStart', function (event, toState) {
var data = toState.data; // Get our state data
var requireLogin = typeof data === 'undefined' ? false : data.requireLogin; // Check to see if we have any data and if so, check to see if we need login rights
var user = account.current() // Get our current user
// If we require login rights and we are not authenticated
if (requireLogin && !user.authenticated) {
// Get our current state
var state = data.state || '';
// Stop processing
event.preventDefault();
// redirect to the login page and pass the state parameter
$state.transitionTo('login', { returnState: state });
}
});
}]);
然后在我的 loginController 上我有这个功能:
self.loginUser = function () {
// Login
self.login = service.login(self.model);
// If we login properly
self.login.promise.then(function (response) {
// If we have a return Url
if (returnState) {
// Go to that url
$state.go(returnState);
} else {
// Otherwise, Redirect to the home page
$state.go('home');
}
});
};
我展示的示例非常有效。但是现在我发现我有更复杂的需求。 我有另一组状态:
$stateProvider.state('designer', {
url: '/:sport/designer',
abstract: true,
templateUrl: '/app/designer/designer.tpl.html',
controller: 'DesignerController',
controllerAs: 'controller'
}).state('designer.team', {
url: '',
templateUrl: '/app/designer/team.tpl.html'
}).state('designer.kit', {
url: '/kit',
templateUrl: '/app/designer/kit.tpl.html'
}).state('designer.design', {
url: '/design',
templateUrl: '/app/designer/design.tpl.html'
}).state('designer.refine', {
url: '/refine',
templateUrl: '/app/designer/refine.tpl.html'
}).state('designer.order', {
url: '/order',
templateUrl: '/app/designer/order.tpl.html'
}).state('designer.save', {
url: '/save',
templateUrl: '/app/designer/save.tpl.html',
data: {
requireLogin: true
}
});
如您所见,这个状态和一些 children 以及最后一个状态(保存)要求用户登录。因为状态继承了它们的参数 parents 我应该是能够做类似的事情:
state: 'designer.save({ sport: :sport })'
但我收到一条错误消息:
Error: Could not resolve 'desginer.save({ sport: :sport })' from state 'login'
现在我假设这是因为 :sport 没有作为字符串传递,但我已经尝试过 alsorts 但我无法让它工作。 有没有更好的方法来处理路由?
我确实尝试过使用 stateChangeStart 函数来获取我们要移动的状态,但我似乎无法访问它。
首先,如果我们查看 the docs,我们可以看到 $state.go
接受以下参数:
- 绝对状态名称
- 参数
- 选项
我没有看到任何地方提到将参数直接放入状态名称是合法的。所以我们有错误消息的原因。 'designer.save({ sport: :sport })'
不是 正确的绝对州名称。
Because states inherit the parameters of their parents
这意味着您不仅可以访问它们,而且在某些情况下它们会自动通过:
Any parameters that are not specified will be inherited from currently defined parameters. This allows, for example, going to a sibling state that shares parameters specified in a parent state. Parameter inheritance only works between common ancestor states, I.e. transitioning to a sibling will get you the parameters for all parents, transitioning to a child will get you all current parameters, etc.
因此,只要您处于 designer
状态或其任何子状态,您就不必提供任何参数。如果你不是,那么你需要找到一种方法将参数作为第二个参数传递给 $state.go
.
感谢user2847643的建议。我实际上想出了一个更好的方法来处理这个问题。 首先,我将 login 状态修改为:
$stateProvider.state('login', {
url: '/account/login',
params: {
returnState: '',
returnParams: {}
},
views: {
// the main template will be placed here (relatively named)
'': {
templateUrl: 'app/account/login/index.tpl.html'
},
// the child views will be defined here (absolutely named)
'register@login': {
templateUrl: 'app/account/login/register.tpl.html',
controller: 'RegisterController',
controllerAs: 'controller'
},
// for column two, we'll define a separate controller
'login@login': {
templateUrl: 'app/account/login/login.tpl.html',
controller: 'LoginController',
controllerAs: 'controller'
}
}
});
如您所见,它接受两个可选参数。 然后我将登录功能修改为:
self.loginUser = function () {
// Login
self.login = service.login(self.model);
// If we login properly
self.login.promise.then(function (response) {
console.log(returnState);
console.log(returnParams);
// If we have a return Url
if (returnState) {
// Go to that url
$state.go(returnState, returnParams);
} else {
// Otherwise, Redirect to the home page
$state.go('home');
}
});
};
现在可以正确调用传递状态和参数(或空对象)的 $state.go 函数。
我实际上将处理 returnStates 的逻辑放在我之前展示的 stateChangeStart 绑定中,所以现在看起来像这样:
$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
var data = toState.data; // Get our state data
var requireLogin = typeof data === 'undefined' ? false : data.requireLogin; // Check to see if we have any data and if so, check to see if we need login rights
var user = account.current() // Get our current user
// If we require login rights and we are not authenticated
if (requireLogin && !user.authenticated) {
// Get our current state
var name = toState.name;
var params = toParams;
// If our state is the login page (i.e. we accessed it directly)
if (name === 'login') {
// Set our state to the homepage
name = 'home';
toParams = {};
}
// Stop processing
event.preventDefault();
// redirect to the login page and pass the state parameter
$state.transitionTo('login', { returnState: name, returnParams: params });
}
});
我们已经做到了。
感谢 r3plica post。我遇到的问题很少,并通过以下方式解决了。如果我错了,有人可以纠正我。
- 你应该使用ui-router最新版本,旧版本不支持params。我正在使用 0.2.13.
- 在控制器中,您需要读取参数为 $state.go($stateParams.returnState, $stateParams.returnParams)
在$stateChangeStart事件中,还需要传递参数fromState,fromParams。这是用来检查fromState是否不是登录,所以你一次又一次地跳过重新加载登录页面。
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){ // var restrictedPage = $.inArray($location.path(),['/landing', '/list','/landing/users']);
var data = toState.data; if(typeof toState.data !== 'undefined' && fromState.name !== 'login'){......} }