Javascript AngularJS - UI 路由器 - 以编程方式添加状态
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25866387/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
AngularJS - UI Router - programmatically add states
提问by khorvat
Is there a way to programmatically add states to $stateProvider after module configuration, in e.g. service ?
有没有办法在模块配置后以编程方式向 $stateProvider 添加状态,例如 service ?
To add more context to this question, I have a situation where I can go with two approaches:
为了给这个问题添加更多上下文,我有一种情况,我可以采用两种方法:
- try to force the reload on the state defined in the module configuration, the problem is that state has a reloadOnSearchset to false, so when I try $state.go('state.name', {new:param}, {reload:true});nothing happens, any ideas ?
- 尝试强制重新加载模块配置中定义的状态,问题是状态的reloadOnSearch设置为false,所以当我尝试$state.go('state.name', {new:param}, {reload:真的}); 没有任何反应,有什么想法吗?
State definition
状态定义
.state('index.resource.view', {
url: "/:resourceName/view?pageNumber&pageSize&orderBy&search",
templateUrl: "/resourceAdministration/views/view.html",
controller: "resourceViewCtrl",
reloadOnSearch: false,
})
- try to programmatically add states that I need to load from a service so routing can work properly. I'd rather go with the first option if possible.
- 尝试以编程方式添加我需要从服务加载的状态,以便路由可以正常工作。如果可能,我宁愿选择第一个选项。
回答by Chris T
See -edit- for updated information
有关更新的信息,请参阅 -edit-
Normally states are added to the $stateProviderduring the config phase. If you want to add states at runtime, you'll need to keep a reference to the $stateProvideraround.
通常状态会$stateProvider在配置阶段添加到。如果要在运行时添加状态,则需要保留对$stateProvider周围的引用。
This code is untested, but should do what you want. It creates a service called runtimeStates. You can inject it into runtime code and then add states.
这段代码未经测试,但应该做你想做的。它创建了一个名为runtimeStates. 您可以将其注入运行时代码,然后添加状态。
// config-time dependencies can be injected here at .provider() declaration
myapp.provider('runtimeStates', function runtimeStates($stateProvider) {
// runtime dependencies for the service can be injected here, at the provider.$get() function.
this.$get = function($q, $timeout, $state) { // for example
return {
addState: function(name, state) {
$stateProvider.state(name, state);
}
}
}
});
I've implemented some stuff called Future Statesin UI-Router Extrasthat take care of some of the corner cases for you like mapping urls to states that don't exist yet. Future States also shows how you can lazy load the source code for runtime-states. Take a look at the source codeto get a feel for what is involved.
我已经在UI-Router Extras中实现了一些称为Future States 的东西,它们为您处理了一些极端情况,例如将 url 映射到尚不存在的状态。Future States 还展示了如何延迟加载运行时状态的源代码。查看源代码以了解所涉及的内容。
-edit- for UI-Router 1.0+
-edit- 用于 UI-Router 1.0+
In UI-Router 1.0, states can be registered and deregistered at runtime using StateRegistry.registerand StateRegistry.deregister.
在 UI-Router 1.0 中,可以在运行时使用StateRegistry.register和注册和注销状态StateRegistry.deregister。
To get access to the StateRegistry, inject it as $stateRegistry, or inject $uiRouterand access it via UIRouter.stateRegistry.
要访问 StateRegistry,请将其注入为$stateRegistry,或$uiRouter通过注入并访问它UIRouter.stateRegistry。
UI-Router 1.0 also includes Future States out of the box which handles lazy loading of state definitions, even synchronizing by URL.
UI-Router 1.0 还包括开箱即用的未来状态,它处理状态定义的延迟加载,甚至通过 URL 同步。
回答by Alex Boisselle
Chris T nailed it! The provider is the way to go. You don't have to slap it onto the window object, saver, more protected, etc.
克里斯 T 搞定了!提供者是要走的路。您不必将其贴在窗口对象、保护程序、更多保护等上。
Cross referencing his answer with this article really helped: http://blog.xebia.com/2013/09/01/differences-between-providers-in-angularjs/#provider
用这篇文章交叉引用他的回答真的很有帮助:http: //blog.xebia.com/2013/09/01/differences-between-providers-in-angularjs/#provider
The solution makes a specific modules $stateProvider during the config block accessible to other modules during their run blocks.
该解决方案使配置块期间的特定模块 $stateProvider 在运行块期间可被其他模块访问。
In my situation I'm dynamically generating dashboard states depending on a user's permissions.
在我的情况下,我根据用户的权限动态生成仪表板状态。
During my config block, my provider is set, passing the module's stateProvider (to be accessed later).
在我的配置块中,我的提供者被设置,传递模块的 stateProvider(稍后访问)。
//in dashboard.module.js
var dashboardModule = angular.module('app.modules.dashboard',[
'app.modules.dashboard.controllers',
'app.modules.dashboard.services',
'app.modules.dashboard.presentations.mileage'
])
.provider('$dashboardState', function($stateProvider){
this.$get = function(PATHS, $state){
return {
addState: function(title, controllerAs, templatePrefix) {
$stateProvider.state('dashboard.' + title, {
url: '/' + title,
views: {
'dashboardModule@dashboard': {
templateUrl: PATHS.DASHBOARD + (templatePrefix ? templatePrefix + '/' : '/') + title + '/' + title + '.view.html',
controller: controllerAs ? controllerAs : null
}
}
});
}
}
}
});
That will make my Dashboard state provider available to other modules, instead of slapping it on the window.
这将使我的仪表板状态提供程序可用于其他模块,而不是将其拍打在窗口上。
Then in my User module's run block (controller), I can access the dashboard's state provider and inject states dynamically.
然后在我的用户模块的运行块(控制器)中,我可以访问仪表板的状态提供程序并动态注入状态。
var UserControllers = angular.module('app.modules.user.controllers', [])
.controller("UserLoginController", ["$state", "$dashboardState", function($state, $dashboardState){
$dashboardState.addState('faq', null, 'content');
$state.go('dashboard.faq');
}]);
回答by Chad Robinson
Yes, it is possible to do this, but because there are caching layers involved it's complex. Alex Feinberg has documented a solution on his blog here:
是的,可以这样做,但是因为涉及缓存层,所以很复杂。Alex Feinberg 在他的博客上记录了一个解决方案:
The tail end of the article includes an example of creating a state by using the stateProvider:
文章的最后包含了一个使用 stateProvider 创建状态的例子:
app.stateProvider.state(ent.lob.name.toLowerCase(), {
url: '/' + ent.lob.name.toLowerCase(),
controller: ent.lob.name.toLowerCase() + 'Controller',
templateUrl: 'lobs/views/' + ent.lob.name.toLowerCase() + '.html'
});

