Andrew Bezzub
Andrew Bezzub

Reputation: 16032

AngularJS: initialize controller with different services

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

Answers (2)

Hung Nguyen
Hung Nguyen

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

ne4istb
ne4istb

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

Related Questions