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 и наследования вида... все доступны в любом дочернем состоянии...

Проверьте, что все здесь.