javascript - start - ui router angular 5
Promesa orden de resoluciĆ³n de dependencia en ui-router angular (4)
He configurado un controlador de nivel superior que se crea una instancia solo cuando una promesa (devuelta por una fábrica de Config
) se resuelve con éxito. Esa promesa básicamente descarga la configuración de la aplicación web, con puntos finales RESTful y así sucesivamente.
$stateProvider
.state(''app'', {
url: ''/'',
templateUrl: ''views/_index.html'',
controller: ''MainCtrl'',
resolve: {
config: ''Config''
}
});
Esta configuración me permite afirmar que la configuración está correctamente cargada antes de que cualquier controlador inferior tenga la oportunidad de usarla.
Ahora necesito inyectar, en un controlador anidado más profundo, otra factory
que usa Config
y que solo funciona cuando se resuelve (considérelo como un contenedor de $resource
que necesita algunas URL de servicios web). Si lo hago:
$stateProvider
.state(''app.bottom.page'', {
url: ''/bottom/page'',
templateUrl: ''views/_a_view.html'',
controller: ''BottomLevelCtrl'',
resolve: {
TheResource: ''MyConfigDependingResource''
}
});
Parece que el orden de evaluación de resolución no sigue la jerarquía del controlador de arriba a abajo, sino de abajo a arriba, por lo tanto:
-
app.bottom.page
es ingresada -
ui-router
intenta resolverMyConfigDependingResource
, pero la inyección falla, porqueConfig
nunca se ha inicializado - La resolución de
ui-router
detiene debido a un error (sin siquiera lanzarError
s, pero ese es otro problema), yConfig
nunca se inicializa mediante el controlador de nivel superior
¿Por qué ui-router
resolviendo las dependencias en orden inverso? ¿Cómo puedo resolver fácilmente mi objeto TheResource
después de que el nivel principal MainCtrl
haya resuelto la Config
(sin depender de $inject
, por supuesto)?
ACTUALIZACIÓN : en el registro de este plnkr puede ver que la resolve
nivel superior se intenta solo después de que el controlador anidado haya iniciado su propio proceso de resolución.
De manera similar a la respuesta de @Kasper Lewau, uno puede especificar una dependencia en los resueltos dentro de un solo estado. Si uno de sus resuelve depende de una o más propiedades de resolución del mismo bloque de resolución. En mi caso, checkS
basa en otros dos resuelve
.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);
}]
}
})
** PD: ** Consulte la sección "Resuelve" del siguiente documento para obtener más detalles sobre el funcionamiento interno de la resolve
.
Estoy de acuerdo con usted en que las resoluciones deben encadenar, y he encontrado muchos problemas en esta área.
Sin embargo, no lo hacen, por lo que la solución que he encontrado es usar mi propia promesa almacenada en un servicio que usted resuelve cuando los datos están completos. He intentado mi mejor esfuerzo para editar su plunkr para trabajar, pero en vano. Sin embargo, ya no estoy golpeando tus errores, así que espero que puedas trabajar desde esto: http://plnkr.co/edit/Yi65ciQPu7lxjkFMBKLn?p=preview
Lo que está haciendo:
Almacena la configuración en un estado junto con un nuevo objeto de promesa
myapp.service(''state'', function($q) {
this.load = $q.defer();
this.config = {}
})
En su primera resolución, almacene su configuración en este servicio y, una vez que esté listo, resuelva la nueva promesa que creamos anteriormente.
myapp.factory(''Config'', function($http, $log, state) {
return $http.get(''example.json'')
.then(function (data) {
angular.extend(state.config, data.data);
state.load.resolve();
});
});
El paso final y más importante es no llamar a nuestro segundo el contenido de la función de resolución del niño hasta que se resuelva nuestra promesa anterior:
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
});
});
Lo principal que debe tener en cuenta es que la configuración ahora está almacenada en un estado. Debería haber maneras de evitar esto, pero así es como lo he hecho antes.
Resuelva los objetos ejecutándose en paralelo, y como tal no sigue una cierta jerarquía. Sin embargo, las resoluciones anidadas son posibles definiendo un objeto de resolución de orden superior como una dependencia de sus resoluciones secundarias.
$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!''.
}]
}
});
Es un mal ejemplo, pero supongo que entiendes lo esencial. Defina el nombre de un objeto de resolución de nivel superior como una dependencia para su resolución de nivel inferior y esperará a que se resuelva primero.
Así es como hemos resuelto la precarga de ciertos datos antes de resolver los objetos de orden inferior, así como los requisitos de autenticación (entre otras cosas).
Buena suerte.
Si bien no se pueden encadenar, puede llamar a uno de otro:
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
}
});