20

How to make blocking http request in AngularJS so that i can use the $http response on very next line?

In the following example, $http object doesn't return the result to the next line so that I can pass this result to fullcalender(), a JavaScript library, because $scope.data returns blank value.

This is the sample code:

$http.get('URL').success(function(data){
    $scope.data = data;
});

$.fullCalender({
    data: $scope.data
});
Ferie
  • 1,358
  • 21
  • 36
Dipak
  • 495
  • 1
  • 4
  • 12
  • Is there any way to avoid this? Javascript is single threaded, and making a synchronous HTTP request will block the ENTIRE BROWSER while it waits for a response. This should not be your preferred solution. – GregL Nov 05 '14 at 06:16
  • 1
    Could you not simply move the call to fullCalendar into the success callback and set data equal to the data arg of the callback? – Scott Nov 05 '14 at 06:17
  • when i use fullcalendar data in callback it is not displaying on template. – Dipak Nov 05 '14 at 06:24
  • 2
    The reason why calendar doesn't trigger is because it is executed not in angular $digest loop. You have to place `$.fullCalendar....` inside success callback and call `$scope.$apply()` after that – Kirill Slatin Jul 15 '15 at 21:55

3 Answers3

2

You can't, you'll need deal with it through promises, but you could try do it like this:

$http.get('URL').success(function(data){
    angular.copy(data, $scope.data);
});

$.fullCalender({
    data: $scope.data
});

but most people would just do

$http.get('URL').success(function(data){
    $.fullCalender({
        data: data
    });
});

If whatever your fullCalender object is doesn't work with async data, you might need to wrap it in something like ng-if or force it to redraw when the data has been supplied. You can also force the controller to not load until the data is loaded by using the route resolve.

John
  • 6,503
  • 3
  • 37
  • 58
2

You can use promises for that.

here is an example:

$scope.myXhr = function(){

    var deferred = $q.defer();

    $http({
        url: 'ajax.php',
        method: 'POST',
        data:postData,
        headers: {'Content-Type': 'application/x-www-form-urlencoded'}
        })
        //if request is successful
        .success(function(data,status,headers,config){

            //resolve the promise
            deferred.resolve('request successful');

        })
        //if request is not successful
        .error(function(data,status,headers,config){
            //reject the promise
            deferred.reject('ERROR');
        });

    //return the promise
    return deferred.promise;
}

$scope.callXhrAsynchronous = function(){

    var myPromise = $scope.myXhr();

    // wait until the promise return resolve or eject
    //"then" has 2 functions (resolveFunction, rejectFunction)
    myPromise.then(function(resolve){
        alert(resolve);
        }, function(reject){
        alert(reject)      
    });

}
yazaki
  • 1,724
  • 1
  • 13
  • 17
Giwwel
  • 347
  • 1
  • 4
2

Here is a practical answer, courtesy of user Kirill Slatin who posted the answer as a comment. Practical use example at the bottom of the answer.

If, like me, you need to use that response object as a scope variable, this should work:

$http.get('URL').success(function(data){

$scope.data = data;
$.fullCalender = $scope.data;
$scope.$apply()
});

$scope.$apply() is what will persist the response object so you can use that data.

-

Why would you need to do this?

I'd been trying to create an "edit" page for my recipes app. I needed to populate my form with the selected recipe's data. After making my GET request, and passing the response data to the $scope.form, I got nothing... $scope.$apply() and Kirill Slatin helped big time. Cheers mate!

Here's the example from my editRecipeController:

  $http.get('api/recipe/' + currentRecipeId).then(
    function (data) {
      $scope.recipe = data.data;
      $scope.form = $scope.recipe;
      $scope.$apply()
    }
);

Hope that helps!

Community
  • 1
  • 1
Bptstmlgt
  • 128
  • 1
  • 12