I’m building an angular application that is going to run on several domains. Since there are different configurations on each domain I'll need to fetch all the variables by doing a call to the server. The call will return a JSON object that contains different rest urls. My problem is that I need to do this call before the 'resolve' step inside the $stateProvider, since I already have a task that is dependent on the configuration object from the server.
What should work here is a really great feature $urlRouterProvider.deferIntercept();
documented here:
$urlRouterProvider
The
deferIntercept(defer)
Disables (or enables) deferring location change interception.
If you wish to customize the behavior of syncing the URL (for example, if you wish to defer a transition but maintain the current URL), call this method at configuration time. Then, at run time, call
$urlRouter.listen()
after you have configured your own$locationChangeSuccess
event handler.
The code snippet from the API documentation:
var app = angular.module('app', ['ui.router.router']);
app.config(function($urlRouterProvider) {
// Prevent $urlRouter from automatically intercepting URL changes;
// this allows you to configure custom behavior in between
// location changes and route synchronization:
$urlRouterProvider.deferIntercept();
}).run(function($rootScope, $urlRouter, UserService) {
$rootScope.$on('$locationChangeSuccess', function(e) {
// UserService is an example service for managing user state
if (UserService.isLoggedIn()) return;
// Prevent $urlRouter's default handler from firing
e.preventDefault();
UserService.handleLogin().then(function() {
// Once the user has logged in, sync the current URL
// to the router:
$urlRouter.sync();
});
});
// Configures $urlRouter's listener *after* your custom listener
$urlRouter.listen();
});
And also, related to this question:
There is working example - plunker
To make it clear, suitable for this use case, let's observe the code of the plunker.
So, firstly we can see the .config()
phase. It does have access to providers but NOT to their services (e.g. $http
). Not yet, services themselves will be available later...
app.config(function ($locationProvider, $urlRouterProvider, $stateProvider)
{
// this will put UI-Router into hibernation
// waiting for explicit resurrection later
// it will give us time to do anything we want... even in .run() phase
$urlRouterProvider.deferIntercept();
$urlRouterProvider.otherwise('/other');
$locationProvider.html5Mode({enabled: false});
$stateProviderRef = $stateProvider;
});
What we did, is set a reference to provider (configurable object), to be used later: $stateProviderRef
.
And the most crucial thing is we STOPPED the UI-Router, and forced him to wait for us with $urlRouterProvider.deferIntercept();
(see the doc and cites above)
There is an extract of the .run()
phase:
app.run(['$q', '$rootScope','$http', '$urlRouter',
function ($q, $rootScope, $http, $urlRouter)
{
// RUN phase can use services (conigured in config phase)
// e.g. $http to load some data
$http
.get("myJson.json")
.success(function(data)
{
// here we can use the loaded stuff to enhance our states
angular.forEach(data, function (value, key)
{
var state = { ... }
...
$stateProviderRef.state(value.name, state);
});
// Configures $urlRouter's listener *after* your custom listener
// here comes resurrection of the UI-Router
// these two important calls, will return the execution to the
// routing provider
// and let the application to use just loaded stuff
$urlRouter.sync();
$urlRouter.listen();
});
}]);
Most important is, that this .run()
was executed just ONCE. Only once. As we require.
We can also use another technique: resolve inside of one super root state, which is parent of all state hierarchy roots. Check all the details here:
Nested states or views for layout with leftbar in ui-router?
$http
in the resolve
- I added another anser. Hope it helps ;) If anything, I'am ready to assit... –
Edraedrea There is another way how to solve the:
How to resolve
$http
request before the execution of theresolve
property inside$stateProvider
?
In case, that we just need to get some $http
result inside of the resolve
, we can do it just like this:
resolve: {
myResolve1:
function($http, $stateParams) {
return $http.get("/api/foos/"+stateParams.fooID);
}
}
This is a snippet from documenation of the [$stateProvider][1]
, section resolve
. We can see, that we return the promise of the $http service: return $http.get()
So, to extend that, to asnwer:
But how can I make the ui-router wait until the promise is resolved?
we can just use return $http.get()
and then .then()
. And inside of it, we have access to returned result - which we can adjust:
myResolve1:
function($http, $stateParams) {
// we still return the promise of the $http.get))
return $http
.get("/api/foos/"+stateParams.fooID)
.then(function(response) {
// but now, the content of resolved property
// will be the first item of the loaded array
return response.data[0];
};
}
}
There is also enahnced solution - in case we need to make this to happen before every state. We just introduce some "root" state as a super parent. It will contain such resolve and all child states will wait until this one is resolved, but just resolved just once. See more here: angular ui-router resolve for parent state
© 2022 - 2024 — McMap. All rights reserved.