0

i'm new to angularjs world and i'm trying to get my head around how to run the whole factry method in angularjs synchronous.

    factory.factory("Connections", function($rootScope, $http, $q) {
     var deferred = $q.defer();
     var connectionStatus;
     console.log("start of factory.factory function");
     $http.get('http://localhost:8088/ecus').success(function(response) {
             deferred.resolve(response);
             console.log(" connection status: " + response.status);
             connectionStatus = 'available';
         })
         .error(function(errResponse) {
             deferred.reject({
                 message: "No connection"
             });
             //   return deferred.promise;
             connectionStatus = 'not available';
             console.log(connectionStatus);
         });
     console.log("end of the factory.factory function");
     return [{
         id: 'conID1',
         pathToImage: 'images/default_test   /eBikeImages/Bionx_creme.png',
         title: 'connection 1',
         status: connectionStatus,
         visible: true,
         favorite: true
     }];
 });

the idea is to get teh value of the connectionStatus from URL call and use it in return value which is the JSON object. the problem is that the factory is being called but the value for the connectionsStatus is not being assigned and the Json is being returned with the undefined value for the connectionStatus. in the console I see that the log for "start of factory" and "end of factory" is being executed before the http calls ! any help would be appreciated :)

Vivz
  • 6,625
  • 2
  • 17
  • 33
kamits
  • 1
  • 2
  • Use .then instead of success. Try to return a promise. – Vivz Jul 03 '17 at 13:12
  • @Vivz what exactly do you mean by returning a promise? because the important part is to get the assigned value of connectionStaus and use it in JSON return value. – kamits Jul 03 '17 at 13:19
  • You might want to use this factory in your controller, so I think it's better if you return a promise from the factory. For more details https://stackoverflow.com/questions/28830003/angular-factory-returning-a-promise – Vivz Jul 03 '17 at 13:23

3 Answers3

0

You are already using promise service, which will helps you run functions asynchronously.

just return $http service function. Which is itself returns promise.

here what i will do,

    factory.factory("Connections", function($rootScope, $http, $q) {

       var deferred = $q.defer();
      var connectionStatus;
      console.log("start of factory.factory function");
             $http.get('http://localhost:8088/ecus').success(function(response) {
             console.log(" connection status: " + response.status);
             connectionStatus = 'available';

            deferred.resolve({
                 id: 'conID1',
                 pathToImage: 'images/default_test   /eBikeImages/Bionx_creme.png',
                 title: 'connection 1',
                 status: connectionStatus,
                 visible: true,
                 favorite: true
             });
     }).error(function(errResponse) {
       connectionStatus = 'not available';
       console.log(connectionStatus);
       deferred.reject({
            message: "No connection",
            status: connectionStatus,
       });
 });
  console.log("end of the factory.factory function");
  return deferred.promise;
});

and caller of factory will read your values by .then funtion

Kaustubh Khare
  • 3,280
  • 2
  • 32
  • 48
  • this is now the error message that I get: angular.js:14110 Error: [$injector:undef] http://errors.angularjs.org/1.5.9/$injector/undef?p0=Connections – kamits Jul 03 '17 at 13:43
  • and still the execution is not synchronous. first I see the logs at the beggining and end of the factory and then the log inside the .then ! – kamits Jul 03 '17 at 13:47
0

You want to run it as synchronous, but you have a dependency on async execution to be finished (i.e. the ajax call here), So the things you can try:

1> Return a promise, and resolve that promise once your call executed and populate the data and resolve with the data, and in the injecting end use .then(function(data){...}) and pass a callback to get the data. or else you can return the promise directly returned by $http. But, since you are writing a separate service it will be better to return with data you are interested for.

2> async and wait of es2017 (new feature, may not support everywhere so far)

3> (not recomended, will block browser for some time) Write your own code to make a synchronous ajax call using XmlHttpRequest as using $http there is no configurable option to do that.

4> Or else, return a reference, and populate that inside object when you get the response from server, and broadcast some meaningful event like Connections.ready . (Its not a generic solution, but will address your issue, since you are using angular and injecting $rootScope in your service).

Enjoy Coding and Async execution handling :)

Koushik Chatterjee
  • 4,106
  • 3
  • 18
  • 32
  • could you please provide code fot the firs case ? this is what I am trying to do but I can not get it right! – kamits Jul 03 '17 at 14:14
  • remove the variable connectionStatus, and from where you are resolving the promise, do something like `deferred.resolve({connectionStatus: 'available'})` (and all other detail you need put in the object). I will also recommend you to resolve the promise again inside catch, instead of rejecting. If you do so you have to again hanle it. So try something like `deferred.resolve({connectionStatus: 'not available'})` inside catch, so in the injecting end you have one common gateway. and also better to use `true/false` instead of available – Koushik Chatterjee Jul 03 '17 at 14:30
0

Please see the updated code, just construct a new response

factory.factory("Connections", function($rootScope, $http, $q) {
     var deferred = $q.defer();
     var connectionStatus;
     console.log("start of factory.factory function");
     $http.get('http://localhost:8088/ecus').success(function(response) {
            var newResponse = {
                'response': response,
                'connectionStatus': 'available'
            };
             deferred.resolve(newResponse);
             console.log(" connection status: " + response.status);
             connectionStatus = 'available';
         })
         .error(function(errResponse) {
            var newResponse = {
                'response': errResponse,
                'connectionStatus': 'not available'
            };

             deferred.reject(newResponse);
             connectionStatus = 'not available';
             console.log(connectionStatus);
         });
     console.log("end of the factory.factory function");
     return [{
         id: 'conID1',
         pathToImage: 'images/default_test   /eBikeImages/Bionx_creme.png',
         title: 'connection 1',
         status: connectionStatus,
         visible: true,
         favorite: true
     }];
 });

and in the controller you will write

<factory name>.then(successFunction, errorFunction);

function SuccessFunction(data){
console.log(data)
}

function errorFunction(data){
console.log(data)
}
Lalit Sachdeva
  • 6,469
  • 2
  • 19
  • 25
  • thanks it was helpful. but when my app starts this is the first page to be loaded and i'm not calling it in any controller.but still the http call is being done after returning the JSON object and that's why the status is still in this code undefined ! – kamits Jul 03 '17 at 14:02
  • so where will this return/output goes from factory? – Lalit Sachdeva Jul 03 '17 at 14:27