Порядковый порядок разрешения зависимостей в angular ui-router
Я установил контроллер верхнего уровня, который создается только тогда, когда обещание (возвращаемое Config
factory) успешно разрешено. Это обещание в основном загружает конфигурацию веб-приложения с конечными точками RESTful и т.д.
$stateProvider
.state('app', {
url: '/',
templateUrl: 'views/_index.html',
controller: 'MainCtrl',
resolve: {
config: 'Config'
}
});
Эта настройка позволяет мне утверждать, что конфигурация должным образом загружена до того, как какой-либо более низкий контроллер получит возможность ее использовать.
Теперь мне нужно добавить в более глубокий вложенный контроллер еще один factory
, который использует Config
и работает только тогда, когда он разрешен (посмотрите на него как на упаковку $resource
, которая нуждается в некоторых URL-адресах веб-сервисов). Если я это сделаю:
$stateProvider
.state('app.bottom.page', {
url: '/bottom/page',
templateUrl: 'views/_a_view.html',
controller: 'BottomLevelCtrl',
resolve: {
TheResource: 'MyConfigDependingResource'
}
});
похоже, что порядок оценки resolve
не соответствует иерархии контроллера сверху вниз, а снизу вверх, поэтому:
-
app.bottom.page
-
ui-router
пытается разрешить MyConfigDependingResource
, но инъекция терпит неудачу,
потому что Config
никогда не инициализировался
- Разрешение
ui-router
прекращается из-за ошибки (даже не выбрасывая Error
s, но эта другая проблема), а Config
никогда не инициализируется контроллером верхнего уровня
Почему ui-router
разрешает зависимости в обратном порядке? Как я могу легко разрешить мой TheResource
объект после, верхний уровень MainCtrl
разрешил Config
(не полагаясь на $inject
, конечно)?
UPDATE: от этот журнал plnkr вы можете видеть, что верхний уровень resolve
выполняется только после вложенный контроллер начал свой собственный процесс разрешения.
Ответы
Ответ 1
Аналогично ответу @Kasper Lewau, можно указать зависимость от разрешений, связанных с одним состоянием. Если одно из ваших разрешений зависит от одного или нескольких свойств разрешения от одного и того же блока разрешений. В моем случае checkS
полагается на два других разрешений
.state('stateofstate', {
url: "/anrapasd",
templateUrl: "views/anrapasd.html",
controller: 'SteofsteCtrl',
resolve: {
currU: function(gamMag) {
return gamMag.checkWifi("jabadabadu")
},
userC: function(gamUser, $stateParams) {
return gamUser.getBipi("oink")
},
checkS: ['currU', 'userC', 'gamMag', function(currU, userC, gamMag) {
return gamMag.check(currU, userC);
}]
}
})
** PS: ** Подробнее о внутренней работе resolve
см. раздел "Разрешает" следующий документ.
Ответ 2
Разрешить объекты, выполняемые параллельно, и поэтому не следует определенной иерархии.
Однако вложенные разрешения возможны путем определения объекта решения более высокого порядка в качестве зависимости от вашего вторичного разрешения.
$stateProvider
.state('topState', {
url: '/',
resolve: {
mainResolveObj: ['$someService', function ($someService) {
return 'I am needed elsewhere!';
}]
}
})
.state('topState.someOtherState', {
url: '/some-other-place',
resolve: {
someOtherResolveObj: ['mainResolveObj', function (mainResolveObj) {
console.log(mainResolveObj); //-> 'I am needed elsewhere!'.
}]
}
});
Какой-то плохой пример, но я понимаю, что вы понимаете суть этого. Определите имя объекта разрешения более высокого уровня как зависимость от вашего решения более низкого уровня, и он будет ждать его разрешения в первую очередь.
Вот как мы решили предварительно загрузить определенные данные перед объектами решения более низкого порядка, а также требования к аутентификации (среди прочего).
Удачи.
Ответ 3
Я согласен с вами в том, что решение должно быть целым, и я столкнулся со многими проблемами в этой области.
Однако они этого не делают, поэтому решение, которое я придумал, заключается в использовании моего собственного обещания, хранящегося в сервисе, который вы разрешаете, когда данные завершены. Я попытался изо всех сил изменить ваш plunkr на работу, но безрезультатно. Я больше не нажимаю на ваши ошибки, поэтому надеюсь, что вы сможете это сделать: http://plnkr.co/edit/Yi65ciQPu7lxjkFMBKLn?p=preview
Что он делает:
Сохраните конфигурацию в состоянии рядом с новым объектом обещания
myapp.service('state', function($q) {
this.load = $q.defer();
this.config = {}
})
При первом разрешении сохраните конфигурацию в этой службе и после того, как вы готовы решить новое обещание, которое мы создали выше.
myapp.factory('Config', function($http, $log, state) {
return $http.get('example.json')
.then(function (data) {
angular.extend(state.config, data.data);
state.load.resolve();
});
});
Последний и самый важный шаг - не называть наш второй контент функции разрешения дочерних элементов до тех пор, пока не будет разрешено наше обещание выше:
myapp.factory('MyConfigDependingResource', function($log, state) {
return state.load.promise.then(function() {
if (!state.config.text) {
$log.error('Config is uninitialized!');
}
else {
// Do wonderful things
}
return
});
});
Главное, что вам нужно знать, это то, что конфигурация теперь хранится в состоянии. Там должны быть пути вокруг этого, но я так и делал это раньше.
Ответ 4
Пока они не могут быть закованы в цепочку, вы можете звонить один из другого:
var resolve2 = ['$stateParams',function($stateParams){
// do resolve 2 stuff
...
return true;
}];
var resolve1 = ['$stateParams',function($stateParams){
// do resolve 1 stuff
...
// now do resolve2 stuff
return $injector.invoke(resolve2,this,{$stateParams:$stateParams});
}];
$stateProvider.state("myState", {
resolve: {
resolve1: resolve1
}
});