ajmajmajma
ajmajmajma

Reputation: 14216

multiple $http with promise using factory, angular

I am attempting to call multiple $http request in a factory which I Am using to flush out multiple inputs with data and set default selections. I Want to then call a promise once all 3 of these are done to call in the real form data (if there is any, sometimes there will not be in which case it will do nothing) to overwrite the defaults in place.

So here is my attempt at this -

the factory I set up a factory to call all 3 inputs and their defaults (I am being sent them individually, i cannot change this for now). It looks like this:

.factory("getDefaults", function() {

return {
    instructions: function() {
        $http({
        method: "GET",
        url: "/getStringDropdown/materials"
    })
    .success(function(data, status, headers, config){
        $scope.instructions.materials = data.text;
    });

    $http({
        method: "GET",
        url: "/getStringDropdown/reinforce"
    })
    .success(function(data, status, headers, config){
        $scope.reinforce = data.options;
        $scope.instructions.reinforce = $scope.reinforce[data.default];
    });

    $http({
        method: "GET",
        url: "/getStringDropdown/procedure"
    })
    .success(function(data, status, headers, config){
        $scope.procedures = data.options;
        $scope.instructions.procedures = $scope.procedures[data.default];
    });
     //return data here? 

    }
  };

})

My question here is - do i have to return the data here? And also can I define the scopes here that are being used (as apposed to in the actual controller). I'm pretty sure this is wrong but I cant' find a good example of how to structure something like this properly.

The call in the contoller

So i the controller my thinking is i would then try something like this -

    getDefaults.instructions().then(function(){
            //possible return data here
            //AFTER data is flushed out call farm data

    $http({
        method: "GET",
        url: "/getSavedFormData/formID"
    })
    .success(function(data, status, headers, config){
        $scope.instructions.materials= data.materials;
        $scope.instructions.procedures = $scope.procedures[data.procedure];
        $scope.instructions.reinforce = $scope.reinfoce[data.reinforcement];
    });

        });

So big picture - I am trying to get these 3 calls to run and populate and THEN the second one. I'm not sure what might or might not be the best approach, factory seemed to make sense based on the trying to consolidate the 3 calls into 1 place with a promise when they are all done. I'm thinking i need to return the data, but it would be pretty nice if i could define the scopes for the controller in the factory. I am still getting my bearing with angular so any/all guidance would be much appreciated. Thanks for reading!!

Upvotes: 1

Views: 1992

Answers (3)

tommybananas
tommybananas

Reputation: 5736

Your service is not aware of your $scope out of the box, nor do you probably want it to be as the whole point of services is to assist with the modularity of your code.

What you probably want to do is actually return the $http promise from your service so that your .success() callback can actually set models on the $scope via closure (being inside the controller).

So your factory would be more like this:

.factory("getDefaults", function() {
  return {
    instructions: $http({ method: "GET", url: "/getStringDropdown/materials" })
  }
});

If you really think you'll never need those http calls separately and you only care about when they all resolve. You could return a $q.all() promise that will resolve when they all resolve:

.factory("getDefaults", function($http, $q) {
  var promise1 = $http({ method: "GET", url: "/getStringDropdown/materials" });
  var promise2 = $http({ method: "GET", url: "/getStringDropdown/materials" });
  var promise3 = $http({ method: "GET", url: "/getStringDropdown/materials" });
  return {
    data: $q.all([promise1,promise2,promise3]),
    anotherCall: $http.get('/anothercallUrl')
  }
});

So now from your controller you could just do:

function myCtrl($scope,getDefaults){
   getDefaults.data.then(function(data){
     //access all three of your promises, their data, and set $scope models here
     getDefaults.anotherCall.success(function(data){
       //or another http call
     });
   };
}

$q.all documentation here: https://docs.angularjs.org/api/ng/service/$q

Upvotes: 3

alpinescrambler
alpinescrambler

Reputation: 1954

You may want to have a look at angular's q$ (https://docs.angularjs.org/api/ng/service/$q)

1.) Create the first three promises that must finish "first"

 var deferred = $q.defer();
$http({
    method: "GET",
    url: "/getStringDropdown/procedure"
})
.success(function(data, status, headers, config){
    deferred.resolve(data);
});
var promise1 = deferred.promise;

2.) Use all method of q$, then call a "then" to the result to execute the second part of your logic

q$.all([promise1, promise2, promise3])
.then(function(results) {
 $http({
    method: "GET",
    url: "/getSavedFormData/formID"
  })
  .success(function(data, status, headers, config){
    $scope.instructions.materials= data.materials;
    $scope.instructions.procedures = $scope.procedures[data.procedure];
    $scope.instructions.reinforce = $scope.reinfoce[data.reinforcement];
 });
});

Upvotes: 1

Narek Mamikonyan
Narek Mamikonyan

Reputation: 4611

Using scopes in factories is not a good idea , my suggestion to not use, about multiple http calls you should use $q.all

example here in fiddle

for each call you should create defered object push it into array then use

$q.all(deferesArray).then(
      function(resp){
         // all requests are resolver , resp is array with resolved datas
        }
  )

Upvotes: 1

Related Questions