Reputation: 16649
I am using AngularJS and ngProgress to display a YouTube-like loading bar at the top of my site.
The bar is started, then new data is loaded in via ajax, and once the request is finished, the bar is completed.
Example:
var TestCtrl = function( $scope, $location, Tests, ngProgress )
{
// start progressbar
ngProgress.start();
$scope.tests = Tests.query(
function()
{
// end progressbar
ngProgress.complete()
}
);
};
Now my question is: How can I integrate this principle higher up in the order of things, such that I don't have to repeat the code for every single controller?
Upvotes: 3
Views: 5207
Reputation: 169
Here is an example using Interceptor:
.factory('interceptorNgProgress', [
'ngProgressFactory', function (ngProgressFactory) {
var complete_progress, getNgProgress, ng_progress, working;
ng_progress = null;
working = false;
getNgProgress = function() {
if(!ng_progress) {
ng_progress = ngProgressFactory.createInstance();
return ng_progress;
}
return ng_progress;
};
complete_progress = function() {
var ngProgress;
if (working) {
ngProgress = getNgProgress();
ngProgress.complete();
return working = false;
}
};
return {
request: function(request) {
var ngProgress;
ngProgress = getNgProgress();
if (request.url.indexOf('.html') > 0) {
return request;
}
if (!working) {
ngProgress.reset();
ngProgress.start();
working = true;
}
return request;
},
requestError: function(request) {
complete_progress();
return request;
},
response: function(response) {
complete_progress();
return response;
},
responseError: function(response) {
complete_progress();
return response;
}
}
}])
.config(function ($httpProvider) {
$httpProvider.interceptors.push('interceptorNgProgress');
});
Upvotes: 1
Reputation: 4876
You could use a service which controls ngProgress (acting like a wrapper over it) and listen for changes in the url.
$locationChangeSuccess
is broadcasted (more info at $location) which we could listen to invoke ngProgress.start()
ngProgress.complete()
explicitly in our controllers OR we could assume that our async functions might take like 5 seconds to be completed and call ngProgress.complete()
using a timer in our wrapper servicengProgress.reset()
You can use the following approach to solve these problems:
angular.module('myApp').factory('Progress', function (ngProgress) {
var timer;
return {
start: function () {
var me = this;
// reset the status of the progress bar
me.reset();
// if the `complete` method is not called
// complete the progress of the bar after 5 seconds
timer = setTimeout(function () {
me.complete();
}, 5000);
},
complete: function () {
ngProgress.complete();
if (timer) {
// remove the 5 second timer
clearTimeout(timer);
timer = null;
}
},
reset: function () {
if (timer) {
// remove the 5 second timer
clearTimeout(timer);
// reset the progress bar
ngProgress.reset();
}
// start the progress bar
ngProgress.start();
}
};
});
To listen for changes in the url and show the progress bar we could use:
angular.module('myApp')
.run(function (Progress) {
$rootScope.$on('$locationChangeSuccess', function () {
Progress.start();
});
}
Now we can manually control the completeness of the status bar by injecting the Progress
service and calling the method Progress.complete()
when all of our async functions have finished (we could also control this from any service that makes async calls):
angular.module('myApp')
.controller('SomeCtrl', function (Progress) {
setTimeout(function () {
Progress.complete();
}, 2000);
});
Upvotes: 2
Reputation: 31640
You apparently already have a Tests
service. Override it so ngProgress
is injected into it and have Tests
always call ngProgress.start()
and ngProgress.complete()
for you in query
.
Upvotes: 0
Reputation: 73
I would put it in an angular directive and then you can pass that into any controller you want to be able to use it.
http://docs.angularjs.org/guide/directive
Edit, thinking about it a service mght be better for this case.
http://docs.angularjs.org/guide/dev_guide.services.creating_services
Upvotes: 0