Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to load data synchronously in AngularJS application

Tags:

angularjs

Now I know that because of the way javascript executes it is recommended that you run all remote requests as async instead of sync. While I agree with that 99% of the time, sometimes you do want to run remote request as a sync instead of a async. For example, loading session data is something I would want to do synchronically as I don't want any views to render until that data is loaded. This plunker shows the issue with loading session data asynchronically (NOTE: I am using $timeout to simulate what would happen with an async call):

http://plnkr.co/edit/bzE1XP23MkE5YKWxRYrn?p=preview

The data property does not load anything because the data is not available when it tries to get it and data2 does only because the data is available when it tries to get it. Now in this case I could just put the session variable on the scope and be done with it but that is not always the case.

Is there a better way to do sync remote calls in an angular application other than using jQuery's .ajax() method (trying to depend on jQuery as little as possible)?

like image 947
ryanzec Avatar asked Jan 20 '26 11:01

ryanzec


2 Answers

If you want the session data to be loaded prior to a controller being loaded, you should included it as as resolve parameter (assuming you are using the $routeProvider).

For example:

angular.module('mymodule', ['ngResource'])

  /* here's our session resource.  we can call Session.get() to retrieve it. */
  .factory('Session', ['$resource', function($resource) {
     return $resource('/api/session.json');
   }])

  /* here's our controller + route definition. */
  .config(['$routeProvider', function($routeProvider) {

    $routeProvider.when('/foo', {
      controller: 'MyCtrl',
      templateUrl: '/templates/foo.html',

      /* the controller will not be loaded until the items
       * below are all resolved! */
      resolve: {
        session: ['$q', 'Session', function($q, Session) {
          var d = $q.defer();
          Session.get(function(session) {
            /* session returned successfully */
            d.resolve(session);
          }, function(err) {
            /* session failed to load */
            d.reject(err);
          });
          return d.promise;
        }]
      }
    });
  }])

  .controller('MyCtrl', ['$scope', 'session', function($scope, session) {
    /* 'session' here is the key we passed to resolve above.
     * It will already be loaded and resolved before this function is called */
    $scope.session = session;
  }]);
like image 92
John Ledbetter Avatar answered Jan 22 '26 05:01

John Ledbetter


Angular is hardcoded to make the requests async. To do it synchronously would take other code, whether custom or from some other library. Here is line 9269 from angular 1.0.7:

xhr.open(method, url, true);

The third param makes it asynchronous.

I would take a step back and think about how you are doing things. You could provide some loading indicator while your async request is going and easily control the loading of a view in the success callback so that it doesn't appear until the data is loaded.

like image 27
Hippocrates Avatar answered Jan 22 '26 07:01

Hippocrates