How to Wait for Promises in AngularJS

In one of my previous blogs – How to Cache Results from Asynchronous Calls in AngularJS, I mentioned a technique that downloads data from remote server via $http service as a promise. This is quite often used in Web application development, for example, you want to save configuration, user preference on remote server and download them on fly.

The previous technique works well, but it may feel a bit strange with all the promise syntax there. After writing the blog, I came to know another technique that can further simplify the experience using the built-in ngRoute.

Lost VMs or Containers? Too Many Consoles? Too Slow GUI? Time to learn how to "Google" and manage your VMware and clouds in a fast and secure HTML5 App.

Download one URL

Let’s take a look at a concrete example that illustrate the usage. It relies on the $routeProvider which resolves all the promises in the resolve part. In our case, it would wait for the LoadService.loadPromise to finish. As you would expect, the loadPromise simply load from a URL via HTTP and assign the value to local variable. Notice the difference of self and this here. If you use “this.data1 = data”, it will not work because with the inner function, the “this” is not the “this” for the service. To solve this, use a variable to pass reference into the inner function.

Once the promise is done, the ngRoute will render the page based on the template and controller. From the controller, you can simply reference the value, not the promise as I showned you before. So you don’t have to write code inside a then function, thesefore the code looks cleaner and easier to read.

<!doctype html>
<html ng-app="doublecloud" >
<head>
  <title>AngularJS Demo for Loaading Data via HTTP</title>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
  <script src="app.js"></script>
</head>
 
<body ng-view></body>
 
</html>
var app = angular.module('doublecloud', []);
 
app.config(function($routeProvider){
  $routeProvider
    .when('/',{
	  controller:'MainCtrl',
      template:'<div>data1:{{data1}}</div>',
      resolve:{
       '' : function(LoadService) { return LoadService.loadPromise; }
    }})
  })
 
app.controller('MainCtrl', function($scope, LoadService) {
  $scope.data1 = LoadService.data1;
});
 
app.service('LoadService', function($http) {
  var self = this;
 
  this.loadPromise = $http.get('data.json').success(function (data) {
      self.data1 = data;
  });
});
This is sample data.

Download Multiple URLs

More often than not, you will have multiple configuration resources to download. You can use multiple promises and add them into the resolve object of $routeProvider part. There are actually a better way to achieve that with much simpler and cleaner syntax.

The key is to use the $q service which can aggregate multiple promises. We can push down the orginal $http promise into the $q.all() as shown in the code. You don’t need to change other part of the code to make it work. Of course, you want to use additional values therefore you need to change the template and controller a bit.

With this generic solution, you can even use it when there is only one URL to download. Whenever you have something new to add, you can copy/paste the existing $http code and only change the name of the URL and what value to assign to.

 
var app = angular.module('doublecloud', []);
 
app.config(function($routeProvider){
  $routeProvider
    .when('/',{controller:'MainCtrl',
    template:'<div>data1:{{data1}}</div><div>data2:{{data2}}</div>',
    resolve:{
      '' : function(LoadService) {
        return LoadService.loadPromise;
      }
    }})
  })
 
app.controller('MainCtrl', function($scope, LoadService) {
  $scope.data1 = LoadService.data1;
  $scope.data2 = LoadService.data2;
});
 
app.service('LoadService', function($http, $q) {
  var self = this;
 
  this.loadPromise = $q.all([
 
    $http.get('data.json').success(function (data) {
      self.data1 = data;
    }),
 
    $http.get('data2').success(function (data) {
      self.data2 = data;
    })
 
  ]);
});

Discussion
Althougth HTTP is one of the top use cases of promise, but it’s not limited there. The above techniques can be applied on any tasks that return promises.

While it works, you probably don’t want to over-use it for fetching big amount of data due to the amount of time which can cause noticeable delay in GUI rendering. For small amount of configuration data, it works perfectly!

This entry was posted in Software Development and tagged , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

  • NEED HELP?


    My company has created products like vSearch ("Super vCenter"), vijavaNG APIs, EAM APIs, ICE tool. We also help clients with virtualization and cloud computing on customized development, training. Should you, or someone you know, need these products and services, please feel free to contact me: steve __AT__ doublecloud.org.

    Me: Steve Jin, VMware vExpert who authored the VMware VI and vSphere SDK by Prentice Hall, and created the de factor open source vSphere Java API while working at VMware engineering. Companies like Cisco, EMC, NetApp, HP, Dell, VMware, are among the users of the API and other tools I developed for their products, internal IT orchestration, and test automation.