vitto_primatti
vitto_primatti

Reputation: 57

Order of execution of $http callbacks

It seems that factory methods execution priority is the highest, so that callbacks has no data to deal with. What is the best way to make this work?

I got this kind of factory

app.factory('jsonService', function($http) {
    return {
        getDistricts: function(callback) {
            $http.get('data/districts.json').success(callback);
        },
        getLocations: function(path,callback) {
            $http.get('data/'+path+'.json').success(callback);
        }
    };
});

And controller

var app = angular.module('sandbox', []);
app.controller('sandboxCtrl',function ($scope,jsonService) {

 //This one works
    $scope.init1= function(){
        jsonService.getDistricts(function(data){
            $scope.districts = data;
            $scope.currentDistrict = $scope.districts[0].name;

             jsonService.getLocations($scope.currentDistrict,function(data){
            $scope.locations1 = data;

        })
        });

    };
    $scope.init1();

    //This one does not 
    $scope.init2= function(){
        jsonService.getDistricts(function(data){
            $scope.districts = data;
            $scope.currentDistrict = $scope.districts[0].name;
        })
        jsonService.getLocations($scope.currentDistrict,function(data){
            $scope.locations1 = data;
        });

    };
    $scope.init2();

});

Here is working plunker

Upvotes: 1

Views: 222

Answers (2)

Brocco
Brocco

Reputation: 64853

Angular has an implementation of promises named $q (documentation) that you should read up upon.

There is a race condition due to the async nature of http calls. Please review the updated code linked to below that shows an example of your code running (successfully) using promises to handle your two calls in succession.

So upon success of your first call it will call your second service method all without using callbacks thanks to the power of promises.

jsonService.getDistricts()
  .success(function(data) {
    $scope.districts = data;
    $scope.currentDistrict = $scope.districts[0].name;
    jsonService.getLocations($scope.currentDistrict)
      .success(function(locationData) {
        $scope.locations = locationData;
      })
  });

updated PLKR

Promise clarification: The raw implementation of basic promises uses then to handle responses and promises returned from $http add additional methods (success, error) that will unpack your data from the response object that you would need to handle if your just use then.

Upvotes: 1

JME
JME

Reputation: 3642

init1() is the correct way of doing this. init2() does work because jsonService.getLocations() is getting invoked before jsonService.getDistritcs() completes. The angular $http service is asynchronous. Since jsonService.getLocations() depends on data from jsonServicd.getDistricts() you must wait until .getDistricts() completes before calling .getLocations(). One way to do that is to call .getLocations() within the .getDitricts() callback, just as you did in init1().

Upvotes: 1

Related Questions