问题描述
我在使用UI-Router-Extras"向应用的运行时阶段添加新状态时遇到问题.
在用户使用UI-Router-Extras"插件ui-router-extras'
这里是对 'UI-Router-Extras' 示例的引用 对于我正在使用的 FutureState 文档,但我觉得我的场景可能与显示的内容略有不同,或者我完全遗漏了一些东西.
PLUNKER 中的示例代码 - 单击登录按钮 -> http://plnkr.co/edit/PQwNQcLNMyPfpke076yy
加载和工作的代码:
我成功地从外部文件中获取了初始 app.config() 延迟加载.就像下面描述的代码:
PUBLIC - 使用UI-Router-Extras"-lazyload/states/public-states.json"的外部初始加载路由
初始应用加载 - 在登录时成功延迟加载公共状态:
'use strict';var app = angular.module('app', ['ui.router', 'ct.ui.router.extras']).config(function ($urlRouterProvider, $stateProvider, $futureStateProvider) {app.stateProvider = $stateProvider;//以后可能需要参考吗?app.futurestateProvider = $futureStateProvider;//以后可能需要参考吗?//可用路由的异步加载 - 即将按角色分类var futureStateResolve = ["$http", function($http) {返回 $http.get("lazyload/states/public-states.json").then(function(response) {angular.forEach(响应数据,功能(状态){$stateProvider.state(state);控制台日志(状态.角色);})})}];$futureStateProvider.addResolve(futureStateResolve);console.log($futureStateProvider);});
下面的代码不起作用
以下是我对不起作用部分的代码:
PRIVATE - 使用UI-Router-Extras"的外部初始加载路由 -lazyload/states/public-states.json"
下面的这个 json 是在用户使用延迟加载和 FutureStates 登录后添加的.到目前为止没有运气:(
[{"name": "应用程序",抽象":真实,"url": "?menu1State","templateUrl": "app/components/core/layout/layout.html","controller": "LayoutCtrl",角色":[级别1"]},{"name": "app.dashboard","url": "/app",意见":{特征": {"templateUrl": "app/components/core/features/features.html",控制器":功能控制"}},角色":[级别1"]},{"name": "app.associations_beanbags","url": "/app/associations/bean-bags?myParam1&myParam2&modalState",意见":{特征": {"templateUrl": "app/components/core/features/associations/bean-bags.html","controller": "豆袋控件"}},角色":[级别2"]}]登录按钮在成功验证后触发状态的延迟创建:
<a id="btn-fblogin" href="" class="btn btn-primary pull-right" ng-click="callNotify(username, password);">登录</a>
发生的情况是,当用户单击登录按钮时,它会模拟成功并调用$scope.callNotify",从而触发您在下面看到的代码.最终发生的事情是一切正常,直到 'app.futurestateProvider.futureState(newState);' 并尝试调用新状态以查看是否添加了 '$state.go('app.dashboard');'.所有这些都会导致出现以下错误:
控制台错误:
错误:无法从状态unauth"解析app.dashboard"在 Object.transitionTo (http://localhost:3000/bower_components/angular-ui-router/release/angular-ui-router.js:2521:17)在 Object.$state.transitionTo (http://localhost:3000/bower_components/ui-router-extras/release/ct-ui-router-extras.js:136:34)在 Object.$state.transitionTo (http://localhost:3000/bower_components/ui-router-extras/release/ct-ui-router-extras.js:874:55)在 Object.$state.transitionTo (http://localhost:3000/bower_components/ui-router-extras/release/ct-ui-router-extras.js:1301:48)在 Object.go (http://localhost:3000/bower_components/angular-ui-router/release/angular-ui-router.js:2454:21)在 http://localhost:3000/app/components/core/auth/auth-service.js:58:13在 http://localhost:3000/bower_components/angular/angular.js:8113:11在wrappedCallback (http://localhost:3000/bower_components/angular/angular.js:11573:81)在wrappedCallback (http://localhost:3000/bower_components/angular/angular.js:11573:81)在 http://localhost:3000/bower_components/angular/angular.js:11659:26
所以在我看来,状态从未像我们预期的那样真正被添加,从而导致一个错误,比如对不起,我没有看到你正在寻找的路线."
'use strict';app.controller('AuthServiceTestCtrl', ['$window','$scope','$http', '$state', function (win, $scope, $http, $state) {$scope.callNotify = function(username,password, $stateProvider, $futureStateProvider) {//通知(用户名,密码);//调用服务并获取返回值/操作var loadedAgain = $http.get("lazyload/states/private-states.json").success(function(response) {if(username == "[email protected]" && 密码 == "abc123"){console.log('有效凭据.登录.');//现在用户已登录注册新的私有路由/状态 - 最好从上面的安全服务器文件 ('private-states.json')var adminModuleFutureStates = [{"name": "应用程序",抽象":真实,"url": "?menu1State","templateUrl": "app/components/core/layout/layout.html","controller": "LayoutCtrl",角色":[级别1"]},{"name": "app.dashboard","url": "/app",意见":{特征": {"templateUrl": "app/components/core/features/features.html",控制器":功能控制"}},角色":[级别1"]},{"name": "app.associations_bean-bags","url": "/app/associations/bean-bags?myParam1&myParam2&modalState",意见":{特征": {"templateUrl": "app/components/core/features/associations/bean-bags.html","controller": "BeanBagsCtrl"}},角色":[级别2"]}];angular.forEach(adminModuleFutureStates, function(newState) {控制台日志(新状态);app.futurestateProvider.futureState(newState);//已在应用程序配置中保存为 VAR 以供日后参考});//最后转到我们刚刚添加的新添加的私有状态之一,它是一个仪表板$state.go('app.dashboard');}});};}]);
我很抱歉没有准备好一个工作示例,我现在正在做,但我想我现在发布这个是为了展示我所拥有的,并可能就我如何进行讨论或解决方案在应用程序已经加载配置等之后,可以在运行时通过我上面列出的控制器将状态加载到 ui-router.
我在这里最终要做的是:
我真的只需要在登录时公开两条安全的公共路由即可.然后,一旦用户登录以前的公共路线,我就会尝试使用新路线添加或装饰现有路线,这些路线现在只允许用户访问其角色提供的路线.安全性对我们来说非常重要,我认为在登录页面上预先加载每条可能的路由没有任何好处,让人们知道 API 或服务器路由是什么,至少无需登录.
我很抱歉我的胡说八道,但我得出的结论是我只是做错了,需要一些额外的眼睛来了解为什么我不能在加载后添加新状态.
真的非常感谢你!
PLUNKER 中的示例代码 - 单击登录按钮 -> http://plnkr.co/edit/PQwNQcLNMyPfpke076yy
我决定改用 $ocLazyLoad 服务,但仍然使用应用程序注入器在应用程序加载并初始配置基本配置后动态添加路由身份验证前的公共路由等.
angular.module("app").configInjector.invoke(['$stateProvider', function ($stateProvider) {
然后在应用程序注入器被设置并且用户被验证并且角色被服务器验证之后,定义允许的 ui-router 视图/路由/状态的 json 响应被循环并动态添加到 ui-路由器状态定义.这些路由在 json 中定义,但使用 $ocLazyLoad 延迟加载的任何附带控制器和视图也是如此.
总的来说,我最终做了以下事情:
angular.module("auth").factory('AuthRouteLoaderFactory', ['$window', '$rootScope', '$http', '$state', '$cookieStore','$location', '$timeout','AuthSession',功能(赢,$rootScope,$http,$state,$cookieStore,$location,$timeout,AuthSession){//私有接口函数 loadPrivateRoutes() {console.log('AuthRouteLoaderFactory :: 加载私有路由');var loadedPrivateRoutes = $http.get("lazyload/states/private-states.json").success(function (response) {angular.module("app").configInjector.invoke(['$stateProvider', function ($stateProvider) {//非常重要 - POST LOGIN ROUTE LOADER/INJECTOR;//动态和服务器确定的 JSON 基于服务器预先制作的特定角色迭代.angular.forEach(响应,功能(状态){如果(!状态.抽象){state.views.feature.resolve[state.views.feature.data.controllerAlias] = ['$ocLazyLoad', function($ocLazyLoad){return $ocLazyLoad.load({"name": state.views.feature.data.controllerAlias,"files": state.views.feature.data.controllerFiles})}];state.views.feature.resolve.isAuthenticated = function(){//检查我们是否是每个惰性负载的有效会话//AuthSession.validateToken();};}console.log('AuthRouteLoaderFactory :: loadPrivateroutes 状态加载 -> ' + state.name);$stateProvider.state(state.name, state);});$state.go('app.dashboard');}]);});}//现在我们加载路由,直到我们调用 API 的/ME 或 Ping 服务,然后成功加载路由if(AuthSession.validateToken()){$rootScope.hideLoader = true;loadPrivateRoutes();console.log('AuthRouteLoaderFactory :: SESSION VALIDATION SUCCESSFUL :: PROCEED');}//公共接口返回 {测试工厂:函数(){console.log('AuthRouteLoaderFactory::testFactory');},isSessionValid: 函数(){返回 $cookieStore.get('fakeLoginSession');},无效会话:函数(){$cookieStore.remove('fakeLoginSession');$location.path('/login.html');},loadRoutes: loadPrivateRoutes};}]);
公共州/路线:
[{"name": "unauth","url": "/","controller": "登录控制","templateUrl": "app/components/core/login/unauth.html",数据": {角色":[公共"]}},{"name": "登录","url": "/登录","controller": "登录控制","templateUrl": "app/components/core/login/unauth.html",数据": {角色":[公共"]}},{"name": "否则","url": "/",数据": {角色":[公共"]}}]私人国家/路线:
[{ "name": "app", "abstract": true, "url": "", "templateUrl": "app/components/core/layout/layout.html", "controller": "LayoutCtrl" },{"name": "app.dashboard",意见":{特征": {"templateUrl": "lazyload/components/core/features/dashboard/dashboard.html","controller": "DashboardCtrl 作为仪表盘",解决": {},数据": {"controllerAlias": "仪表板","controllerFiles": ["lazyload/components/core/features/dashboard/dashboard-controller.js"]}}}},{"name": "app.associations_role-type",意见":{特征": {"templateUrl": "lazyload/components/core/features/associations/role-type.html","controller": "RoleTypeCtrl 作为 roleType",解决": {},数据": {"controllerAlias": "roleType","controllerFiles": ["lazyload/components/core/features/associations/role-type-controller.js"]}}}}]I am having problems with adding new states to the runtime phase of my app using 'UI-Router-Extras'.
I have been trying for quite some time now to get new states attached and loaded AFTER a user has successfully authenticated using the 'UI-Router-Extras' plugin 'ui-router-extras'
Here is a reference to the 'UI-Router-Extras' Examples for the FutureState documentation that i'm using, but I feel like maybe my scenario is either slightly different that what's shown or I'm missing something altogether.
EXAMPLE CODE IN PLUNKER - CLICK LOGIN BUTTON -> http://plnkr.co/edit/PQwNQcLNMyPfpke076yy
Code Below Loads and Works:
I was successful in getting the initial app.config() lazy loaded from an external file. Like the code describes below:
PUBLIC - External Initially loaded Routes using 'UI-Router-Extras' - 'lazyload/states/public-states.json'
[
{
"name": "unauth",
"url": "/",
"controller": "LoginCtrl",
"templateUrl": "app/components/core/login/login.html",
"roles": ["public"]
},
{
"name": "otherwise",
"url": "/",
"roles": ["public"]
}
]
Initial App Load - Successful Lazy Load of Public States To Begin with On a Login:
'use strict';
var app = angular.module('app', ['ui.router', 'ct.ui.router.extras'])
.config(function ($urlRouterProvider, $stateProvider, $futureStateProvider) {
app.stateProvider = $stateProvider; // MIGHT NEED REFERNCE LATER?
app.futurestateProvider = $futureStateProvider; // MIGHT NEED REFERNCE LATER?
// ASYNC LOAD OF ROUTES AVAILABLE - SOON TO BE BY ROLE
var futureStateResolve = ["$http", function($http) {
return $http.get("lazyload/states/public-states.json").then(function(response) {
angular.forEach(response.data, function(state) {
$stateProvider.state(state);
console.log(state.roles);
})
})
}];
$futureStateProvider.addResolve(futureStateResolve);
console.log($futureStateProvider);
});
Code Below Does NOT work
Below is my code for the part that does not work:
PRIVATE - External Initially loaded Routes using 'UI-Router-Extras' - 'lazyload/states/public-states.json'
This json below is meant to be added after user login using lazy loading and FutureStates. So far no luck :(
[
{
"name": "app",
"abstract": true,
"url": "?menu1State",
"templateUrl": "app/components/core/layout/layout.html",
"controller": "LayoutCtrl",
"roles": ["level1"]
},
{
"name": "app.dashboard",
"url": "/app",
"views": {
"feature": {
"templateUrl": "app/components/core/features/features.html",
"controller": "FeatureCtrl"
}
},
"roles": ["level1"]
},
{
"name": "app.associations_beanbags",
"url": "/app/associations/bean-bags?myParam1&myParam2&modalState",
"views": {
"feature": {
"templateUrl": "app/components/core/features/associations/bean-bags.html",
"controller": "BeanbagsCtrl"
}
},
"roles": ["level2"]
}
]
Login button triggering the lazy creation of states after successful authentication:
<a id="btn-fblogin" href="" class="btn btn-primary pull-right" ng-click="callNotify(username, password);">Login</a>
What happens is when a user clicks on a login button it mocks the success and calls '$scope.callNotify' triggering the code you see below. What ends up happening is everything works up until the 'app.futurestateProvider.futureState(newState);' and the trying to call the new state to see if was added '$state.go('app.dashboard');'. All of this results in an error that states the following:
Console Error:
Error: Could not resolve 'app.dashboard' from state 'unauth'
at Object.transitionTo (http://localhost:3000/bower_components/angular-ui-router/release/angular-ui-router.js:2521:17)
at Object.$state.transitionTo (http://localhost:3000/bower_components/ui-router-extras/release/ct-ui-router-extras.js:136:34)
at Object.$state.transitionTo (http://localhost:3000/bower_components/ui-router-extras/release/ct-ui-router-extras.js:874:55)
at Object.$state.transitionTo (http://localhost:3000/bower_components/ui-router-extras/release/ct-ui-router-extras.js:1301:48)
at Object.go (http://localhost:3000/bower_components/angular-ui-router/release/angular-ui-router.js:2454:21)
at http://localhost:3000/app/components/core/auth/auth-service.js:58:13
at http://localhost:3000/bower_components/angular/angular.js:8113:11
at wrappedCallback (http://localhost:3000/bower_components/angular/angular.js:11573:81)
at wrappedCallback (http://localhost:3000/bower_components/angular/angular.js:11573:81)
at http://localhost:3000/bower_components/angular/angular.js:11659:26
So what this looks like to me is that the states never really got added when we expected, thus causing an error saying something to the likes of "Sorry, i don't see the route you are looking for."
'use strict';
app.controller('AuthServiceTestCtrl', ['$window','$scope','$http', '$state', function (win, $scope, $http, $state) {
$scope.callNotify = function(username,password, $stateProvider, $futureStateProvider) {
//notify(username, password); // CALL SERVICE AND GET A RETURN VALUE / ACTION
var loadedAgain = $http.get("lazyload/states/private-states.json").success(function(response) {
if(username == "[email protected]" && password == "abc123"){
console.log('Valid Credentials. Logging In.');
// NOW THAT USER IS LOGGED IN REGISTER NEW PRIVATE ROUTE / STATES - PREFERABLY FROM THE SECURED SERVER FILE ('private-states.json') ABOVE
var adminModuleFutureStates = [
{
"name": "app",
"abstract": true,
"url": "?menu1State",
"templateUrl": "app/components/core/layout/layout.html",
"controller": "LayoutCtrl",
"roles": ["level1"]
},
{
"name": "app.dashboard",
"url": "/app",
"views": {
"feature": {
"templateUrl": "app/components/core/features/features.html",
"controller": "FeatureCtrl"
}
},
"roles": ["level1"]
},
{
"name": "app.associations_bean-bags",
"url": "/app/associations/bean-bags?myParam1&myParam2&modalState",
"views": {
"feature": {
"templateUrl": "app/components/core/features/associations/bean-bags.html",
"controller": "BeanBagsCtrl"
}
},
"roles": ["level2"]
}
];
angular.forEach(adminModuleFutureStates, function(newState) {
console.log(newState);
app.futurestateProvider.futureState(newState); // WAS SAVED AS A VAR IN APP CONFIG FOR LATER REFERENCE
});
// FINALLY GO TO ONE OF THE NEWLY ADDED PRIVATE STATES WE JUST ADDED WHICH IS A DASHBOARD
$state.go('app.dashboard');
}
});
};
}]);
I'm very sorry for not having a working example ready, I'm on it right now, but i figured i'd post this now to show what I do have and possibly get a discussion or solution as to how I can load states to ui-router at runtime via my controller listed above after the application has already loaded the config etc..
What I'm trying to ultimately do here is this:
I really need to only expose two safe public routes to begin with on login. Then once a user logs in the previous public routes stay and i'm trying to add or decorate the existing routes with new ones that now allow the user to only have access to the routes their role provides. Security for us is extremely important and I do not see any benefit whatsoever loading every possible route upfront on a login page letting someone know what out api or server routs are without at least being logged in.
I'm very sorry for rambling but I've come to the conclusion that I'm just flat doing it wrong and need some extra eyes to maybe catch why i can't add new states post load.
Seriously thank you so much!
EXAMPLE CODE IN PLUNKER - CLICK LOGIN BUTTON -> http://plnkr.co/edit/PQwNQcLNMyPfpke076yy
I decided to use the $ocLazyLoad service instead but still using an app injector to add routes dynamically after the app has loaded and been initially configured with basic public routes before authentication etc..
angular.module("app").configInjector.invoke(['$stateProvider', function ($stateProvider) {
Then after the app injector was setup and the user was authenticated and a role(s) was validated by the server a json response defining the allowed ui-router views / routes / states are looped over and added dynamically to the ui-router state definitions. These routes are defined in the json but so is any accompanying controllers and views that are lazy loaded using $ocLazyLoad.
Overall what I ended up doing was the following:
angular.module("auth")
.factory('AuthRouteLoaderFactory', ['$window', '$rootScope', '$http', '$state', '$cookieStore','$location', '$timeout','AuthSession',
function(win, $rootScope, $http, $state, $cookieStore, $location, $timeout, AuthSession) {
// PRIVATE INTERFACE
function loadPrivateRoutes() {
console.log('AuthRouteLoaderFactory :: LOADING PRIVATE ROUTES');
var loadedPrivateRoutes = $http.get("lazyload/states/private-states.json").success(function (response) {
angular.module("app").configInjector.invoke(['$stateProvider', function ($stateProvider) {
// VERY IMPORTANT - POST LOGIN ROUTE LOADER / INJECTOR;// DYNAMIC AND SERVER DETERMINED JSON ITERATED BASED ON SPECIFIC ROLES PRE-MADE BY SERVER.
angular.forEach(response, function (state) {
if(!state.abstract){
state.views.feature.resolve[state.views.feature.data.controllerAlias] = ['$ocLazyLoad', function($ocLazyLoad){return $ocLazyLoad.load({"name": state.views.feature.data.controllerAlias,"files": state.views.feature.data.controllerFiles})}];
state.views.feature.resolve.isAuthenticated = function(){
// CHECK IF WE ARE A VALID SESSION FOR EACH LAZY LOAD
//AuthSession.validateToken();
};
}
console.log('AuthRouteLoaderFactory :: loadPrivateroutes state loaded -> ' + state.name);
$stateProvider.state(state.name, state);
});
$state.go('app.dashboard');
}]);
});
}
// FOR NOW WE LOAD ROUTES ANYWAY UNTIL WE CALL API'S /ME OR PING SERVICE, THEN ON SUCCESS WE LOAD ROUTES
if(AuthSession.validateToken()){
$rootScope.hideLoader = true;
loadPrivateRoutes();
console.log('AuthRouteLoaderFactory :: SESSION VALIDATION SUCCESSFUL :: PROCEED');
}
// PUBLIC INTERFACE
return {
testFactory: function() {
console.log('AuthRouteLoaderFactory :: testFactory');
},
isSessionValid: function(){
return $cookieStore.get('fakeLoginSession');
},
invalidateSession: function(){
$cookieStore.remove('fakeLoginSession');
$location.path('/login.html');
},
loadRoutes: loadPrivateRoutes
};
}
]);
Public States / Routes:
[
{
"name": "unauth",
"url": "/",
"controller": "LoginCtrl",
"templateUrl": "app/components/core/login/unauth.html",
"data": {
"roles": ["public"]
}
},
{
"name": "login",
"url": "/login",
"controller": "LoginCtrl",
"templateUrl": "app/components/core/login/unauth.html",
"data": {
"roles": ["public"]
}
},
{
"name": "otherwise",
"url": "/",
"data": {
"roles": ["public"]
}
}
]
Private States / Routes:
[
{ "name": "app", "abstract": true, "url": "", "templateUrl": "app/components/core/layout/layout.html", "controller": "LayoutCtrl" },
{
"name": "app.dashboard",
"views": {
"feature": {
"templateUrl": "lazyload/components/core/features/dashboard/dashboard.html",
"controller": "DashboardCtrl as dashboard",
"resolve": {},
"data": {
"controllerAlias": "dashboard",
"controllerFiles": ["lazyload/components/core/features/dashboard/dashboard-controller.js"]
}
}
}
},
{
"name": "app.associations_role-type",
"views": {
"feature": {
"templateUrl": "lazyload/components/core/features/associations/role-type.html",
"controller": "RoleTypeCtrl as roleType",
"resolve": {},
"data": {
"controllerAlias": "roleType",
"controllerFiles": ["lazyload/components/core/features/associations/role-type-controller.js"]
}
}
}
}
]
这篇关于“UI-Router-Extras" - App.Config() 已加载后无法附加/添加新的“FutureState"对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!