0

I am trying to run an $http function when my AngularJS application first loads.

This $http function needs to finish before any of the controllers in my application could properly function. How would I go about doing this? This sounds like a promise, but it sounds like I would be creating a promise in each controller...

I currently have the function that I want to run first like this:

app.run(function() {

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

      // success function. The data that I get from this HTTP call will be saved to a service.

    }).error(function(error) {

    });

});

However, sometimes the controller will load before the http call finishes.

3
  • What data does this request load? Commented Aug 22, 2015 at 16:21
  • This loads an ID number that is used for all subsequent requests. The ID is saved in a service. Commented Aug 22, 2015 at 17:30
  • remember to mark answer as accepted so that other new people will not struggle Commented Aug 24, 2015 at 19:01

2 Answers 2

2

The problem

Angular is not dynamic, you cannot add controller dynamically neither factory, etc. Also you cannot defer controller bootstrap, angular loads everything together, and it's quite disadvantage (will be fixed in Angular 2)

The cure

But javascript itself has very important feature - closure, which works anywhere, anytime.
And angular has some internal services that can be injected outside of angular ecosystem, even into browser console. Those services injected as shown below. We technically could use anything else (jQuery.ajax, window.fetch, or even with XMLHttpRequest), but let's stick with total angular solution

var $http_injected = angular.injector(["ng"]).get("$http");

The act

First of all, we defer whole angular app bootstrap, inject http service. Then you make your needed request, receive data and then closure get's to work, we pass received data into some service, or we could also assign in to some angular.constant or angular.value but let's just make demo with angular.service, so when your service has data, bootstrap whole app, so that all controllers get initialized with your needed data
Basically that kind of tasks solved like this

<body>
  <div ng-controller="Controller1">
    <b>Controller1</b>
    {{text}}
    {{setting.data.name}}
  </div>
  <hr>
  <div ng-controller="Controller2">
   <b>Controller2</b>
    {{text}}
    {{setting.data.name}}
  </div>
  <script>
    //define preloader
    var $http_injected = angular.injector(["ng"]).get("$http");
    $http_injected.get('http://jsonplaceholder.typicode.com/users/1').then(function(successResponse) {

      //define app
      angular.module('app', []); 

      //define test controllers
      //note, usually we see 'controller1 loaded' text before 'settings applied', because controller initialized with this data, but in this demo, we will not see 'controller1 loaded' text, as we use closure to assign data, so it's instantly changed
      angular.module('app').controller('Controller1', function($scope, AppSetting) {
        $scope.text = 'controller1 loaded';
        $scope.setting = AppSetting.setting;
        $scope.$watch('setting', function(e1 ,e2){
          $scope.text = 'settings applied'
        });
      });
      angular.module('app').controller('Controller2', function($scope, AppSetting) {
        $scope.text = 'controller2 loaded';
        $scope.setting = AppSetting.setting;
        $scope.$watch('setting', function(e1 ,e2){
          $scope.text = 'settings applied'
        });
      });

      //define test services, note we assign it here, it's possible
      //because of javascript awesomeness (closure)
      angular.module('app').service('AppSetting', function() {
        this.setting = successResponse;
      });

      //bootstrap app, we cannot use ng-app, as it loads app instantly
      //but we bootstrap it manually when you settings come
      angular.bootstrap(document.body, ['app']);
    });
  </script>
</body>

Plunker demo

Sign up to request clarification or add additional context in comments.

Comments

0

You can do this when you configure your routes

app.config(['$routeProvider', function ($routeProvider) {
  $routeProvider
    .when('/', {
      controller: 'MainCtrl',
      templateUrl: 'main.html',
      resolve: {
        data: ['$http',
          function($http)
          {
            return $http.get('/api/data').then(
                function success(response) { return response.data.rows[0]; },
                function error(reason)     { return false; }
              );
          }
        ]
      }
    });
}]);

Similar question: AngularJS - routeProvider resolve calling a service method

AngularJS: $routeProvider when resolve $http returns response obj instead of my obj

Heres a plunkr I found using a service, which is what I would recommend. http://plnkr.co/edit/XKGC1h?p=info

4 Comments

This will have to be the topmost state
I don't think so he wants data to be loaded..he wants to load configuration setting at run phase
I am trying to figure out if this is the best way to solve my problem. While this solution would work, I want to avoid writing this for every controller. I only need the data loaded once, which I will save to a service (I need to put that in my original question...)
Now I see. You have one controller above the others. This makes sense.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.