Reputation: 1295
I'm attempting to use the angular-busy directive to trigger a loading indicator on state change. The directive template takes a promise (cg-busy='myPromise'), and I'm using ui-router for my routing. What is the best way to trigger the loading indicator on state change from company.list to company.detail so that the indicator is shown while the promises are being resolved? My thought is to create a blank promise on $stateChangeStart, and pass that into the cg-busy template, but that doesn't seem to be working.
HTML:
<div cg-busy='myPromise'></div>
<div class="h1"><h1>Companies</h1>
</div>
<table class="table table-striped table-bordered">
<table class="table table-striped table-bordered">
<tr class="h4">
<td>Company Name</td>
<td>Drugs owned</td>
</tr>
<tr ng-repeat="Item in List">
<td><a ui-sref=".detail.overview({ id:Item.id})">{{ Item.label }} <span ng-show="Item.parent_ticker.length"> ({{ Item.parent_ticker }})</span> </a></td>
<td>{{ Item.metric_applications_count }}</td>
</tr>
</table>
</table>
routes:
angular.module('company').config(function($stateProvider) {
$stateProvider.state('company', {
url: '/company',
abstract: true,
views: {
'nav': { templateUrl: 'app/main.nav.html' },
'main': { templateUrl: 'app/company/company.html' },
'list@company': { templateUrl: 'app/company/company.list.html', controller: 'CompanyListCtrl' },
'footer@': { templateUrl: 'app/main.footer.html' }
}
});
$stateProvider.state('company.list', {url: '',views: {} });
$stateProvider.state('company.detail', {
url: '/{id:[0-9]{1,4}-[0-9]{1,4}}',
resolve: {
Overview: function($stateParams, companyService){
var d = companyService.getOverview($stateParams.id);
return d;
},
Products: function($stateParams, companyService){
var d = companyService.getProducts($stateParams.id);
return d;
},
Revenues: function($stateParams, companyService){
var d = companyService.getRevenues($stateParams.id);
// not a promise
return d;
}
});
company ctrl:
angular.module('company').controller('CompanyListCtrl', function ($rootScope, $scope, $state, $stateParams, $q, utilService, companyService) {
$scope.List = companyService.getAll().$object;
$rootScope.$on("$stateChangeStart", function (ev, to, toParams, from, fromParams) {
$scope.myPromise = $q.defer();
console.log('stateChangeStart');
console.log($scope.myPromise);
});
});
redacted routes for brevity.
Upvotes: 1
Views: 6522
Reputation: 211
I decide to solve this problem same way as you suggest: 1) I add route event listeners in the main module, when I define the route options:
.run(function ($route, $rootScope, $location, $q) {
var routeDeferred;
$rootScope.$on('$routeChangeStart', function () {
routeDeferred = $q.defer();
$rootScope.changingRoutePromise = routeDeferred.promise;
});
$rootScope.$on('$routeChangeSuccess', function () {
routeDeferred.resolve();
});
$rootScope.$on('$routeChangeError', function () {
routeDeferred.reject();
});
});
2) Next, in my controller I create special promise which will be resolved when all deferred objects will be resolved (custom controller promises and route promises):
saveDataAndLoadNextRoutePromise = $q.defer();
3) Last and most important step in Controller: I subscribe on my custom controller`s promise which post data and define the logic of the redirect to the next route:
Sessions.post(data).then(function () {
$location.path('/nextstep');
// After route was changed we need to listen when all resolved params in RouteProvider will be resolved.
//So, because Js is event-oriented lang we need to allow new $routeChangeStart event to be fired first.
//In that way we exclude subscription on routeDeferred in that stack of events in order to $routeChangeStart event fired first as I said,
setTimeout(function() {
$rootScope.changingRoutePromise.then(function() {
saveDataAndLoadNextRoutePromise.resolve();
}, function() {
saveDataAndLoadNextRoutePromise.reject();
});
}, 0);
},function () {
saveDataAndLoadNextRoutePromise.reject();
$scope.isSubmitted = false;
});
4) Add the cg-busy directive with div block in HTML template page related to the Controller:
<div cg-busy="saveSessionAndLoadNextRoutePromise">
<!-- My page -->
</div>
5) To the recap, this solution allows:
Upvotes: 3