0

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.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
lycosis
  • 131
  • 2
  • 12
  • 1
    I think you need to work with `$q` promises: (1) initialise `deferred = $q.defer();` , (2) gather results `$q.all(promises).then((res) => { deferred.resolve(res); });` , (3) return a promise `return deferred.promise;`, then your controller can get result with: `myService.doSomeWork(...).then((res) => { var statusMessage = res; })` – Aleksey Solovey Nov 28 '17 at 16:46
  • This worked, thank you. Could you write out an answer so that I can award it to you? – lycosis Nov 28 '17 at 18:13
  • Using `$q.deferred` with promise-based APIs is probematic. For more infromation, see [Is this a “Deferred Antipattern”?](https://stackoverflow.com/questions/30750207/is-this-a-deferred-antipattern). – georgeawg Nov 28 '17 at 19:28

2 Answers2

1

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.

georgeawg
  • 48,608
  • 13
  • 72
  • 95
0

You can do a callback from the service like

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

 $q.all(promises)
   .then(function(res) {
  //do a callback

  callback(res)

   }, function(err) {
       console.log("error:", err);

   }
  );      
};

and in your controller you can receive the result

  function doWork() {
  myService.doSomeWork(function(result){
 //handle the result
});

}

Padmanabha Vn
  • 624
  • 1
  • 14
  • 33
  • Using a callback like that is problematic. If any of the promise have an error the callback will never be called. For more information, see [Why are Callbacks from Promise `.then` Methods an Anti-Pattern](https://stackoverflow.com/questions/35660881/why-are-callbacks-from-promise-then-methods-an-anti-pattern). – georgeawg Nov 28 '17 at 18:51
  • @georgeawg yeah make sense ! – Padmanabha Vn Nov 29 '17 at 11:24