Directive for lazyloading data in AngularJS

All we need is an easy explanation of the problem, so here it is.

I’m currently learning Angular and trying to figure out a good pattern for lazyloading data and structuring code.

I’m making an responsive web application, and I would like do be able to define that some parts of the web-page are to be hidden from the view (preferably using media queries).

The data fetched for the hidden directives or views is then redundant.

The difference can be substantial from a desktop to a mobile view, and I would like the application to be as light as possible on the mobile perfomance wise and network usage wise.

What is a good approach for making a good architecture that could reprimend this issue?

What if the directive could check if it was currently visible (both within the current viewport and for example not within a hidden parent nor display: none.

I’ve provided an example usage of such a directive, but I would like some pointers to how this could be implemented.

The directive could take an expression that pointed to a callback function that should be fired when the component is visible and within 200px of the viewport.

Note: The following is a fictional example with no good use case.

<!-- Check if the device has some feature, for example touch, and hide content based on results -->
<div ng-show="current.device.touch">
    <users lazyload="{userList: dataservice.getUsers | filter:search}" treshold="200px" placeholder="emptyUserlist">
    </users>
</div>

How good/bad of an idea is this?

The dataservice is a more abstracted service that gets its data from $resource and cache containers.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Angular doesn’t support lazy-loading as a feature, but anything can still be lazy loaded!

The key is in the config function:

var providers = {};

var app = angular.module('myApp', []);
app.config(function(
  $controllerProvider,
  $compileProvider,
  $routeProvider,
  $filterProvider,
  $provide
) {
  providers.controllerProvider = $controllerProvider;
  providers.compileProvider    = $compileProvider;
  providers.routeProvider      = $routeProvider;
  providers.filterProvider     = $filterProvider;
  providers.provide            = $provide;
});

Now you can use the cached providers to lazy-load (register) Angular features.

Lazy-load a controller:

function myCtrl($scope) {
 //etc
}
providers.controllerProvider.register('myCtrl', myCtrl);

Lazy-load a directive:

function myDirectiveName() {
  //etc
}
providers.compileProvider.directive('myDirectiveName', myDirectiveName);

For a practical and more advanced example, See my answer on this post (click). in which I lazy load views and their controllers from external files while scrolling down the page.

Simple demonstration:

Live demo here (click)

<div lazy></div>

Angular logic:

var providers = {};

var app = angular.module('myApp', []);
app.config(function(
  $controllerProvider,
  $compileProvider,
  $routeProvider,
  $filterProvider,
  $provide
) {
  providers.controllerProvider = $controllerProvider;
  providers.compileProvider    = $compileProvider;
  providers.routeProvider      = $routeProvider;
  providers.filterProvider     = $filterProvider;
  providers.provide            = $provide;
});

app.directive('lazy', function() {
  return {
    restrict: 'A',
    compile: function(element, attrs) {
      providers.controllerProvider.register('myCtrl', myCtrl);
      providers.compileProvider.directive('myDirectiveName', myDirectiveName);
      var span = angular.element('<span></span>')
        .attr('my-directive-name', '')
        .attr('ng-controller', 'myCtrl');
      element.append(span);
    }
  };
});

function myDirectiveName() {
  return {
    restrict: 'A',
    compile: function(element, attrs) {
      var str = 'This text came from a lazy-loaded directive {{anotherString}}';
      element.text(str);

    }
  };
}
function myCtrl($scope) {
  $scope.anotherString = 'and this text came from a lazy-loaded controller!';
}

Method 2

Angular does not currently have the ability to do lazy loading. However, Misko (the creator of Angular) mentions in this recently meetup that lazy loading is on the product roadmap for the near future:

http://www.youtube.com/watch?v=Dro-hLSQhoc

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply