Search code examples
angularjsangular-promiseangularjs-service

Sync Service's Async-Response to Controller Variable


I am having a hard time using promises and passing information between a service and controller.

The code below functions, in that it makes the calls, I get the promises back, I perform work on them, etc. I want to pass status messages back to the controller now, but I can't figure out to return them to the controller.

How can I sync myService's non-promise response with my controller variable? Or should I just be returning the $q.all promise back to the controller and then having the controller call the statusService?

Ideally, I want the controller to just "fire and forget" and wait for a status response so I can update a modal.

Controller

function doWork() {
  myService.doSomeWork();

  // what I'm going for:
  // var statusMessage = myService.doSomeWork(sharedDataService.onThisThing);
}

Service

factory.doSomeWork = function() {        
  var promises = [
    queryApi("firstApiCall"), 
    queryApi("secondApiCall")
  ];

  $q.all(promises)
    .then(function(res) {
      workService.doSomething(res[0].data, res[1].data);
      console.log("response:", res);
      // I want to return a string, or object, back to a variable in my controller
      //return statusService.getStatusMessage(res[0]);
    }, function(err) {
      console.log("error:", err);
      //return statusService.getStatusMessage(err);
    }
  );      
};

function queryApi(url) {
  return $http.get(url);
}

Any help would be appreciated.


Solution

  • In AngularJS, asynchronous services should return a promise. To transform promise data in a service, be sure to return the transformed data to the .then method handler function:

    factory.doSomeWork = function() {        
      var promises = [
        queryApi("firstApiCall"), 
        queryApi("secondApiCall")
      ];
    
       ̲r̲e̲t̲u̲r̲n̲ $q.all(promises)
        .then(function successHandler(res) {
          workService.doSomething(res[0].data, res[1].data);
          console.log("response:", res);
          // I want to return a string, or object, back to a variable in my controller
           ̲r̲e̲t̲u̲r̲n̲ transformedData;
        }, function rejectionHandler(err) {
          console.log("error:", err);
           ̶/̶/̶r̶e̶t̶u̶r̶n̶ ̶s̶t̶a̶t̶u̶s̶S̶e̶r̶v̶i̶c̶e̶.̶g̶e̶t̶S̶t̶a̶t̶u̶s̶M̶e̶s̶s̶a̶g̶e̶(̶e̶r̶r̶)̶;̶
           ̲t̲h̲r̲o̲w̲ statusService.getStatusMessage(err);
        }
      );      
    };
    

    It is important to use a throw statement in rejection handlers. Otherwise the rejected promise will be converted to a successful promise.

    In the controller:

    function doWork() {
      var promise = myService.doSomeWork();
    
      promise.then(function(transformedData) {
          console.log(transformedData);
      }).catch(function(err) {
          console.log(err);
      });
    
      // what I'm going for:
      // var statusMessage = myService.doSomeWork(sharedDataService.onThisThing);
    }
    

    For more information, see You're Missing the Point of Promises.