moh_abk
moh_abk

Reputation: 2164

Best way to initialize a controller with several ajax requests

I have 2 $http functions that I call using ng-init because the data they return populates the page.

ng-init = "getOpen(); getClosed();"

Is this the best way?

First function;

$scope.getOpen = function () {
    $http({
        method: 'post',
        url: "http://www.example.co.uk/php/open-get.php",
        data: $.param({ 'location' : $scope.l, 
                       'time' : $scope.t,
                       'day' : $scope.d,
                       'type' : 'get_restopen' }),
        headers: {'Content-Type': 'application/x-www-form-urlencoded'}
    }).
    success (function(data, status, headers, config){
        if(data.success && !angular.isUndefined(data.data) ){
            $scope.open = data.data;
        } else {
            $scope.open = [];
        }
    }).
    error(function(data, status, headers, config) {
        //$scope.messageFailure(data.message);
    });
}

Second function;

$scope.getClosed = function () {
    $http({
        method: 'post',
        url: "http://www.example.co.uk/php/closed-get.php",
        data: $.param({ 'location' : $scope.l, 
                       'time' : $scope.t,
                       'day' : $scope.d,
                       'type' : 'get_restopen' }),
        headers: {'Content-Type': 'application/x-www-form-urlencoded'}
    }).
    success (function(data, status, headers, config){
        if(data.success && !angular.isUndefined(data.data) ){
            $scope.closed = data.data;
        } else {
            $scope.closed = [];
        }
    }).
    error(function(data, status, headers, config) {
        //$scope.messageFailure(data.message);
    });
}

Everything works great. My question I guess is this an efficient way of doing things in AngularJS? I'm new to angular so just seeking guidance.

1 - Are my $http executed simultaneously? Or is one completed before the other one is started?

2 - Is there any need to introduce $q or promises into my code? The functions are independent of each other

3 - How can I detect when all $http request have completed regardless of if successful or not

Is the below code correct?

$q.all([$scope.getOpen, $scope.getClosed]).then(function() {
     //Both requests have been completed and I shall now set a bolean
     $scope.compelete = true;
});

Upvotes: 0

Views: 530

Answers (3)

Deblaton Jean-Philippe
Deblaton Jean-Philippe

Reputation: 11398

I have 2 $http functions that I call using ng-init because the data they return populates the page.

ng-init = "getOpen(); getClosed();"

Is this the best way?

As said into angular documentation :

This directive can be abused to add unnecessary amounts of logic into your templates. There are only a few appropriate uses of ngInit, such as for aliasing special properties of ngRepeat, as seen in the demo below; and for injecting data via server side scripting. Besides these few cases, you should use controllers rather than ngInit to initialize values on a scope.

You can find it here : https://docs.angularjs.org/api/ng/directive/ngInit

you should avoid using ng-init into your templates. The recommended usage for initiating something into a controller is to call a private function directly inside your controller.

I also recommend to read that style guide about angular :
https://github.com/johnpapa/angular-styleguide

1 - Are my $http executed simultaneously? Or is one completed before the other one is started?

The 2 calls are started almost simultaneously. Then, javascript holds a stack of callbacks he has to execute when he gets answers from your server. Just press F12 into your browser and find a "network" tab to see all your requests being launched.

Furthermore, ´.success´ is deprecated now. You should rather use ´.then´ https://docs.angularjs.org/api/ng/service/$http#deprecation-notice

2 - Is there any need to introduce $q or promises into my code? The functions are independent of each other

Not in this case. You could use $q.all([promise1, promise2]) if you wanted to execute something after both calls had been executed

3 - How can I detect when all $http request have completed regardless of if successful or not

Have a look at $httpInterceptors. Let share you a piece of code I implemented

angular.module("myModule").factory("myHttpInterceptor", [
    "LoadingService",
    "$q",
    "Alert",
    function (LoadingService, $q, Alert) {

        function requestInterceptor(config) {
            LoadingService.increaseCounter();
            return config;
        }

        function responseInterceptor(response) {
            LoadingService.decreaseCounter();
            return response;
        }
   // ...

Is the below code correct?

$q.all([$scope.getOpen, $scope.getClosed]).then(function() {
     //Both requests have been completed and I shall now set a bolean
     $scope.compelete = true;
});

nope because you still the promise to be returned by your function. Also, ´.success´ does not implement the chaining of promises. You now HAVE to use ´.then()´

$scope.getOpen = function () {
    return $http({
        // config
    }).
    then(function(data, status, headers, config){
        //handling success
    },(function(data, status, headers, config) {
        //handling error
    });

Summary :

angular.module("yourApp").controller("someController", ["$scope", "$q"
    function($scope, $q){

        // init
        init();

        // Shared functions

        $scope.getOpen = function () {
          return $http({
             method: 'post',
             url: "http://www.example.co.uk/php/open-get.php",
             data: $.param({ 'location' : $scope.l, 
                   'time' : $scope.t,
                   'day' : $scope.d,
                   'type' : 'get_restopen' }),
             headers: {'Content-Type': 'application/x-www-form-urlencoded'}
          });

        $scope.getClosed = function () {
          return $http({
            // config
          });

        // private functions
        function init(){
             var promises = [];

             promises.push($scope.getOpen());
             promises.push($scope.getClosed());

             $q.all(promises).then(function(datas){
                  // Here, you know both calls have been successfull
                  // datas[0] is the result of $scope.open()
                  $scope.open = datas[0].data;
                  $scope.complete = true;

             }, function(errors){
                  $scope.complete = true;
                  // You fall here if one of your calls has failed
             });
        }

    }
]);

Upvotes: 0

WABBIT0111
WABBIT0111

Reputation: 2313

$http is asynchronous, so your 2 calls should be executed in parallel. If you really need to boil the 2 functions down to one, and/or you need to check all $http requests have completed, you can use $q.all Angularjs $q.all

Upvotes: 0

Sébastien Renauld
Sébastien Renauld

Reputation: 19672

  1. Assuming you call both methods yourself somewhere, yes. $http calls are async by default

  2. Already done, $http actually returns a promise!

  3. promise.all() is an elegant way to do so without modifying the return of the promise. It is effectively a completion watcher. More details over on the promise reference

Upvotes: 1

Related Questions