Reputation: 16032
I have a "please wait, in progress" page. It is implemented with Angular controller: controller sends requests to the server once every few seconds to check if long running task is finished. If task is finished it redirects user to the next page. There is also a service that "knows" how to check the status of the job. Simplified versions of controller and service:
controller('MyCtrl', ["$scope", "$timeout", "MyService",
function($scope, $timeout, MyService) {
$scope.checkStatus = function() {
var request = MyService.fetch_status();
request.success(function(statusData) {
if (statusData.in_progress) {
$timeout(function() {
$scope.checkStatus();
}, 2000)
} else {
window.location = statusData.redirect_to;
}
});
};
$scope.checkStatus();
}]);
factory('MyService', ['$http', function($http){
return {
fetch_status : function() {
return $http({
url: '/job_status',
method: 'GET',
headers: { 'Accept': 'application/json' }
});
}
};
}]);
I want to reuse the same controller on a different page. This new page looks very similar, but it checks status of a different long running task and uses different URL. Is there a way to initialize the same controller with different service that "knows" how to check status of the task? Or is there a way to configure service to send request to a different URL? What is the AngularJS way to do this?
Upvotes: 0
Views: 113
Reputation: 66
I think there are some ways to fulfill your requirement
Solution 1
You can move the whole fetch status logic to MyService.checkStatus() and this function returns a promise. So from any controller, you just need to inject MyService and call checkStatus() function.
factory('MyService', ['$http', '$q', '$timeout', function($http, $q, $timeout) {
return {
checkStatus : function() {
var deferred = $q.defer();
$http({
url: '/job_status',
method: 'GET',
headers: { 'Accept': 'application/json' }
}).success(function(data) {
if (statusData.in_progress) {
$timeout(function() {
this.checkStatus(url, callback);
}, 2000);
} else {
deferred.resolve(data);
}
}).error(function(err) {
deferred.reject(err);
});
return deferred.promise;
}
};
};
Controller
controller('MyCtrl', ["$scope", "$timeout", "MyService",
function($scope, $timeout, MyService) {
MyService.checkStatus().then(function(statusData) {
// redirect or other logic here
window.location = statusData.redirect_to
}, function(err) {
// handle error
});
;
}]);
Solution 2
Use $rootScope.$broadcast('checkingStatus')
to broadcast an event to start checking status. Also broadcast another event as soon as getting status data $rootScope.$broadcast('checkStatusCompleted', statusData)
.
Then from each controller, register listeners
$scope.$on('checkingStatus', function(event, args) {
// show status
});
$scope.$on('checkStatusCompleted', function(event, args) {
// redirect
});
Solution 3
Use socket-io for async request like this.
Upvotes: 1
Reputation: 672
You can use route parameter "resolve" to preconfigure some stuff for different URLs
In your case it will be something like this (could be with mistakes):
var app = angular.module('app', []);
app.config(function($routeProvider) {
$routeProvider
.when('/link1', {
templateUrl: 'link1.html',
controller: 'MyCtrl',
resolve: {
MyService: MyServiceLink1
}
})
.when('/link2', {
templateUrl: 'link2.html',
controller: 'MyCtrl',
resolve: {
MyService: MyServiceLink2
}
});
)
app.factory('MyServiceLink1', ['$http', function($http){
return {
fetch_status : function() {
return $http({
url: '/job_status',
method: 'GET',
headers: { 'Accept': 'application/json' }
});
}
};
}]);
app.factory('MyServiceLink2', ['$http', function($http){
return {
fetch_status : function() {
return $http({
url: '/other_job_status',
method: 'GET',
headers: { 'Accept': 'application/json' }
});
}
};
}]);
Upvotes: 1