AngularJS load bar for VisualForce remoting

While there are modules out there to automatically add loading bars using angular http interceptors, when using VisualForce remoting, the actual retrieval of data is deferred to visual force, effectively hiding the request. So, how do you show a loading bar when using this technology? Or how do you deal with multiple directives that all call remoting methods at the same time and are asynchronous? Here’s one way…

Our solution used a directive and a service. The directive handled watching the service to see if stuff was being loaded or not. The load bar html would be shown or hidden based on this.

The service contained an array and 2 functions to add or remove from this array based on a key that would be passed to it. So anything in the app that needed to use a load bar could just add to the load bar service array before the operation, and then remove from it when the operation completed. So technically speaking its not showing progress of the operation, but its giving an indication that something’s happening. It also means that if there are multiple components on screen that all call remote services, each of these can add to the load bar array and the load bar will remain visible until there are no more elements in the load bar array.

Here’s an example…

Dashboard

dashboard

The application we built this for was a salesforce community that includes a dashboard. The dashboard shows current subscriptions and an overview of different services. Each of these is a discrete element on the page and each makes a call to the VisualForce remoting manager.

Current products

This panel is responsible for showing the current list of products a user has, with the ability to show different services for that product. There can be a maximum of 4 of these, each making a call to the remoting service.

Other services overview

The overview panels, of which there are 3, show most recent activity and links to view more details.

Each of these directives calls a service, which in turn calls the VisualForce remoting manager. Since all calls go through this service, the loadbar service can be called at a common point.

So for the subscription panel, the code would be…

vfRemotingService.getSubscriptions(vm.accountId, vm.family, vm.selectedSubscription.id)
  .then(function(results) {
  //...

The overview panels would call the service like this…

vfRemotingService.getOverview(vm.accountId, vm.type)
  .then(function(results) {
  //...

The actual ‘vfRemotingService’ calls the VisualForce manager. In this service, a cache key is generated for the item to be loaded. It is necessary in this case to manually add items to a cache, since we’re not using angular’s $http service. We found the package ‘angular-cache‘ to be great in this regard, enhancing angular’s native caching mechanism with a number of features. Take a look at the code…

var cache = args.getCacheCallback; // 1
if (cache.results !== undefined) { // 2
  return cache.results;
}
ttbLoadingService.addLoadingElement(cache.cacheKey); // 3
  1. The first bit gets the cache object based on parameters passed from the directive. If the item isn’t already in the cache, a cache key is created and returned.
  2. If the item is already cached, this is immediately returned to the calling directive
  3. An entry is added to the load bar services’ array using the cache key. As well as adding the cache key to its array, it also sets a service level variable called ‘isLoading’ to true.

Any other directives that need to call the VisualForce remoting manager go through this step, so they add elements to the loadbar service array.

The loadbar directive

The loadbar directive is simple bit of html that sits on the main template and watches the loadbar service to see if the ‘isLoading’ variable is true. If it is, it just shows itself.

var watch = $scope.$watch(
function () {
  return ttbLoadingService.isLoading;
},
function (loading) {
  vm.loading = loading;
}
);

The template for the loadbar directive is pretty simple…

<div class="loadbar" ng-show="vm.loading"><ng-transclude></ng-transclude></div>

This means that any presentation stuff can just go inside the main loadbar directive.

Hiding the loadbar

When a call to the VisualForce remoting manager is complete (either success or fail), the ‘vfRemoting’ service calls the loadbar service to remove the relevant entry from its array based on the cache key. Here’s the code…

function removeLoadingElement (id) {
  if (loadingElements.indexOf(id) > -1) {
    loadingElements.splice(loadingElements.indexOf(id), 1);
  }

  if (loadingElements.length === 0) {
    service.isLoading = false;
  }
}

The last bit is important. If there are no more elements in the array, the ‘isLoading’ variable is set to false, which is being watched by the loadbar directive. When that happens, it means all load operations have finished, so hide the loadbar.

Conclusion

That’s about it! A fairly simple but effective way of showing a loading element regardless of how many things are loading or when any of them are complete.

Leave a Reply