Reputation: 4440
I am new to Angular
, and am attempting to do some page blocking while content loads. This content includes ajax
requests and some other things, all wrapped into controllers.
Previously, I was handling this with a simple queue system using $.Deferred
in jQuery, but since the way the program "flows" in Angular is fundamentally ... not like that, I'm at a bit of a loss. I'm having a hard time thinking of a way to "tell" my program/module/app that "Yes. I am done loading. You are finished now".
Has anyone else experienced this and discovered a solution to it?
My first thought was to just call events at the end of each controller, but that has yielded some mixed results. There has to be a more professional, reliable solution.
Upvotes: 1
Views: 106
Reputation: 2140
One way to do this might be to create a Service and inject it into each of the controllers, create a function called register which takes a promise pushes it into an array within the service. You could then listen for when all promises are resolved, and load the page.
I would imagine you would need some sort of basic timer promise as well to solve the edge case at the beginning of page load, when the controllers have yet to register their promises.
Within the controllers you would register your promise for the entire controller, or for individual functions, that is up to you, I would create 1 promise per controller with var deferred = $q.defer() Scheduler.register(deferred.promise), then resolve deferred when all other promises had been resolved.
Here's a simple example: http://jsfiddle.net/4mf1pkLj/62/
$window.ready() is called when all promises are resolved within scheduler
.controller('OtherCtrl', ['$scope', '$q', 'scheduler',
function($scope, $q, scheduler) {
var differed = $q.defer()
$scope.state = "waiting"
//do some blocking ajaxy thing
setTimeout(function() {
differed.resolve()
$scope.state = "ready"
}, 5000);
scheduler.register(differed.promise)
}
])
.service('scheduler', ['$http', '$q', '$window',
function($http, $q, $window) {
var promises = [];
var finished = $q.defer().promise
this.register = function(promise) {
promises.push(promise)
finished = wait()
}
function wait() {
return $q.all(promises)
}
function listen() {
finished.then(function() {
//render your content
$window.ready()
})
}
//wait until everything is registered
setTimeout(function(){listen()},200)
}
Upvotes: 1
Reputation: 3172
ngRouter module permits to just do that with the resolve property. It will delay view rendering till all data is loadedThe complete doc can be found here: https://docs.angularjs.org/api/ngRoute
A basic example (from the doc):
angular.module('yourApp', ['ngRoute']);
angular.module('yourApp')
.config(function($routeProvider) {
$routeProvider
.when('/Book/:bookId', {
templateUrl: 'book.html',
controller: 'BookController',
resolve: {
// I will cause a 1 second delay
delay: function ($q, $timeout) {
var delay = $q.defer();
$timeout(delay.resolve, 1000);
return delay.promise;
}
}
})
.when('/Book/:bookId/ch/:chapterId', {
templateUrl: 'chapter.html',
controller: 'ChapterController'
});
});
Your view will not be rendered before the promise delay is resolved.
Upvotes: 1