javascript AngularJS ui-router:如何为所有路由全局解析典型数据?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28237952/
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: how to resolve typical data globally for all routes?
提问by Sray
I have an AngularJS service which communicates with the server and returns translations of different sections of the application:
我有一个 AngularJS 服务,它与服务器通信并返回应用程序不同部分的翻译:
angular
.module('utils')
.service('Translations', ['$q','$http',function($q, $http) {
translationsService = {
get: function(section) {
if (!promise) {
var q = $q.defer();
promise = $http
.get(
'/api/translations',
{
section: section
})
.success(function(data,status,headers,config) {
q.resolve(result.data);
})
.error(function(data,status,headers,config){
q.reject(status);
});
return q.promise;
}
}
};
return translationsService;
}]);
The name of the section is passed as the section
parameter of the get
function.
该部分的名称作为函数的section
参数传递get
。
I'm using AngularJS ui-router module and following design pattern described here
我正在使用 AngularJS ui-router 模块并遵循此处描述的设计模式
So I have the following states config:
所以我有以下状态配置:
angular.module('app')
.config(['$stateProvider', function($stateProvider) {
$stateProvider
.state('users', {
url: '/users',
resolve: {
translations: ['Translations',
function(Translations) {
return Translations.get('users');
}
]
},
templateUrl: '/app/users/list.html',
controller: 'usersController',
controllerAs: 'vm'
})
.state('shifts', {
url: '/shifts',
resolve: {
translations: ['Translations',
function(Translations) {
return Translations.get('shifts');
}
]
},
templateUrl: '/app/shifts/list.html',
controller: 'shiftsController',
controllerAs: 'vm'
})
This works fine but as you may notice I have to explicitly specify translations
in the resolve parameter. I think that's not good enough as this duplicates the logic.
这工作正常,但您可能会注意到我必须translations
在解析参数中明确指定。我认为这还不够好,因为这重复了逻辑。
Is there any way to resolve translations globally and avoid the code duplicates. I mean some kind of middleware.
有什么方法可以全局解析翻译并避免代码重复。我的意思是某种中间件。
I was thinking about listening for the $stateChangeStart
, then get translations specific to the new state and bind them to controllers, but I have not found the way to do it.
我正在考虑监听$stateChangeStart
,然后获取特定于新状态的翻译并将它们绑定到控制器,但我还没有找到这样做的方法。
Any advice will be appreciated greatly.
任何建议将不胜感激。
Important note:
In my case the resolved translations object
must contain the translations data, not service/factory/whatever.
重要说明:在我的情况下,已解决的translations object
必须包含翻译数据,而不是服务/工厂/任何东西。
Kind regards.
亲切的问候。
采纳答案by Sray
Though this is a very old question, I'd like to post solution which I'm using now. Hope it will help somebody in the future. After using some different approaches I came up with a beautiful angularjs pattern by John Papa
虽然这是一个非常古老的问题,但我想发布我现在正在使用的解决方案。希望它会在将来对某人有所帮助。在使用了一些不同的方法后,我想出了一个由约翰·帕帕 (John Papa) 编写的漂亮的 angularjs 模式
He suggest using a special service routerHelperProvider
and configure states as a regular JS object. I'm not going to copy-paste the entire provider here. See the link above for details. But I'm going to show how I solved my problem by the means of that service.
他建议使用特殊服务routerHelperProvider
并将状态配置为常规 JS 对象。我不会在这里复制粘贴整个提供程序。有关详细信息,请参阅上面的链接。但我将展示我如何通过该服务解决我的问题。
Here is the part of code of that provider which takes the JS object and transforms it to the states configuration:
这是该提供程序的部分代码,它接受 JS 对象并将其转换为状态配置:
function configureStates(states, otherwisePath) {
states.forEach(function(state) {
$stateProvider.state(state.state, state.config);
});
I transformed it as follows:
我将其转换如下:
function configureStates(states, otherwisePath) {
states.forEach(function(state) {
var resolveAlways = {
translations: ['Translations', function(Translations) {
if (state.translationCategory) {
return Translations.get(state.translationCategory);
} else {
return {};
}
}],
};
state.config.resolve =
angular.extend(state.config.resolve || {}, resolveAlways || {});
$stateProvider.state(state.state, state.config);
});
});
And my route configuration object now looks as follows:
我的路由配置对象现在如下所示:
{
state: ‘users',
translationsCategory: ‘users',
config: {
controller: ‘usersController'
controllerAs: ‘vm',
url: ‘/users'.
templateUrl: ‘users.html'
}
So what I did:
所以我做了什么:
I implemented the resolveAlways
object which takes the custom translationsCategory
property, injects the Translations
service and resolves the necessary data. Now no need to do it everytime.
我实现了resolveAlways
采用自定义translationsCategory
属性的对象,注入Translations
服务并解析必要的数据。现在不需要每次都这样做。
回答by Radim K?hler
Let me show you my approach. There is a working plunker
让我告诉你我的方法。有一个工作plunker
Let's have a translation.json
like this:
让我们有一个translation.json
这样的:
{
"home" : "trans for home",
"parent" : "trans for parent",
"parent.child" : "trans for child"
}
Now, let's introduce the super parent stateroot
现在,我们来介绍一下超级父状态root
$stateProvider
.state('root', {
abstract: true,
template: '<div ui-view=""></div>',
resolve: ['Translations'
, function(Translations){return Translations.loadAll();}]
});
This super root state is not having any url
(not effecting any child url). Now, we will silently inject that into every state:
这个超级根状态没有任何url
(不影响任何子网址)。现在,我们将悄悄地将其注入每个状态:
$stateProvider
.state('home', {
parent: 'root',
url: "/home",
templateUrl: 'tpl.html',
})
.state('parent', {
parent: 'root',
url: "/parent",
templateUrl: 'tpl.html',
})
As we can see, we use setting parent
- and do not effect/extend the original state name.
正如我们所见,我们使用设置parent
- 并且不影响/扩展原始状态名称。
The root state is loading the translations at one shot via new method loadAll()
:
根状态通过新方法一次性加载翻译loadAll()
:
.service('Translations', ['$http'
,function($http) {
translationsService = {
data : {},
loadAll : function(){
return $http
.get("translations.json")
.then(function(response){
this.data = response.data;
return this.data;
})
},
get: function(section) {
return data[section];
}
};
return translationsService;
}])
We do not need $q
at all. Our super root state just resolves that once... via $http
and loadAll()
method. All these are now loaded, and we can even place that service into $rootScope
:
我们根本不需要$q
。我们的超级根状态只是解决了一次……通过$http
和loadAll()
方法。所有这些现在都已加载,我们甚至可以将该服务放入$rootScope
:
.run(['$rootScope', '$state', '$stateParams', 'Translations',
function ($rootScope, $state, $stateParams, Translations) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
$rootScope.Translations = Translations;
}])
And we can access it anyhwere like this:
我们可以像这样访问它:
<h5>Translation</h5>
<pre>{{Translations.get($state.current.name) | json}}</pre>
Wow... that is solution profiting almost from each feature coming with UI-Router... I'd say. All loaded once. All inherited because of $rootScope and view inheritance... all available in any child state...
哇...这是几乎从 UI-Router 附带的每个功能中获利的解决方案...我想说。全部加载一次。由于 $rootScope 和视图继承而继承的所有...在任何子状态都可用...
Check that all here.
检查所有这里。