AngularJS ui-router: как разрешать типичные данные по всему миру для всех маршрутов?
У меня есть служба 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;
}]);
Название раздела передается как параметр section
функции get
.
Я использую модуль uu-router от AngularJS и следующий шаблон проектирования, описанный здесь
Итак, у меня есть следующие состояния 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'
})
Это работает отлично, но, как вы можете заметить, я должен явно указать translations
в параметре разрешения. Я думаю, что это не так хорошо, как это дублирует логику.
Есть ли способ разрешить переводы по всему миру и избежать дубликатов кода. Я имею в виду какое-то промежуточное ПО.
Я думал о прослушивании $stateChangeStart
, а затем получал переводы, специфичные для нового состояния, и привязывал их к контроллерам, но я не нашел способ сделать это.
Любые советы будут оценены в значительной степени.
Важное примечание:
В моем случае разрешенный translations object
должен содержать данные трансляции, а не service/factory/whatever.
С уважением.
Ответы
Ответ 1
Хотя это очень старый вопрос, я бы хотел опубликовать решение, которое я использую сейчас. Надеюсь, это поможет кому-то в будущем.
После использования некоторых разных подходов я придумал красивый рисунок angularjs от Джона Папа
Он предлагает использовать специальную службу routerHelperProvider
и настраивать состояния как обычный объект JS. Я не собираюсь копировать весь провайдер здесь. Подробнее см. Ссылку выше. Но я покажу, как я решил свою проблему с помощью этой службы.
Вот часть кода этого провайдера, который берет объект JS и преобразует его в конфигурацию состояний:
function configureStates(states, otherwisePath) {
states.forEach(function(state) {
$stateProvider.state(state.state, state.config);
});
Я преобразовал его следующим образом:
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);
});
});
И мой объект настройки маршрута теперь выглядит следующим образом:
{
state: ‘users’,
translationsCategory: ‘users’,
config: {
controller: ‘usersController’
controllerAs: ‘vm’,
url: ‘/users’.
templateUrl: ‘users.html'
}
Итак, что я сделал:
Я реализовал объект resolveAlways
, который принимает пользовательское свойство translationsCategory
, внедряет службу Translations
и разрешает необходимые данные. Теперь не нужно делать это каждый раз.
Ответ 2
Позвольте мне показать вам мой подход. Там является рабочим плунжером
Пусть есть translation.json
:
{
"home" : "trans for home",
"parent" : "trans for parent",
"parent.child" : "trans for child"
}
Теперь представим супер родительское состояние root
$stateProvider
.state('root', {
abstract: true,
template: '<div ui-view=""></div>',
resolve: ['Translations'
, function(Translations){return Translations.loadAll();}]
});
Это супер-корневое состояние не имеет никакого url
(не влияет на какой-либо дочерний url). Теперь мы будем тихо вводить это в каждое состояние:
$stateProvider
.state('home', {
parent: 'root',
url: "/home",
templateUrl: 'tpl.html',
})
.state('parent', {
parent: 'root',
url: "/parent",
templateUrl: 'tpl.html',
})
Как мы видим, мы используем установку parent
- и не влияем/не расширяем исходное состояние.
Корневое состояние загружает переводы одним выстрелом с помощью нового метода 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;
}])
Нам вообще не нужно $q
. Наше супер-корневое состояние просто решает, что однажды... через $http
и loadAll()
метод. Все они теперь загружены, и мы можем даже разместить эту службу в $rootScope
:
.run(['$rootScope', '$state', '$stateParams', 'Translations',
function ($rootScope, $state, $stateParams, Translations) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
$rootScope.Translations = Translations;
}])
И мы можем получить к нему доступ вот так:
<h5>Translation</h5>
<pre>{{Translations.get($state.current.name) | json}}</pre>
Вау... это решение, приносящее прибыль почти из каждой функции, идущей с UI-Router... Я бы сказал. Все загружены один раз. Все унаследованы из-за $rootScope и наследования вида... все доступны в любом дочернем состоянии...
Проверьте, что все здесь.