Angular Lazy Load Image Directive

In this example below you will see how to do a Angular Lazy Load Image Directive with some HTML / CSS and Javascript

Thumbnail
This awesome code was written by 007design, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright 007design ©

Technologies

  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>Angular Lazy Load Image Directive</title>
  
  
  
      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  <div data-ng-app="app">
  <img data-lazy-load="//placehold.it/50x200"/>
  <img data-lazy-load="//placehold.it/50x60"/>
  <img data-lazy-load="//placehold.it/50x70"/>
  <img data-lazy-load="//placehold.it/50x80"/>
  <img data-lazy-load="//placehold.it/50x90"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
  <img data-lazy-load="//placehold.it/50x50"/>
</div>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js'></script>

  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/007design/angular-lazy-load-image-directive-BpPzYw */
img {
  border: 1px solid black;
  margin-bottom: 10px;
  display: block;
  opacity: 0;
}
img.loaded {
  opacity: 1;
}
img.loading {
  opacity: 1;
  transition: opacity linear 2s;
}


/*Downloaded from https://www.codeseek.co/007design/angular-lazy-load-image-directive-BpPzYw */
angular.module('app', [])
.service('lazyLoadQ', ['$q', function($q) {
  let scope = this;
  scope.pending = false;
  let queue = [];
  
  const load = function(o) {
    let q = $q.defer();
    setTimeout(function() {
      const viewportOffset = o.elem[0].getBoundingClientRect();
      if (window.innerHeight + window.scrollY >= viewportOffset.top) {
        o.scope.src = o.attrs.lazyLoad;
        if (o.onload)
          o.elem.addClass('loaded')
        else
          o.elem.addClass('loading');
        o.scope.$apply();
      }
      if (o.elem[0].complete)
        q.resolve();
      else
        load(o).then(q.resolve);
    },0);
    return q.promise;
  };
  
  const process = function() {
    if (queue.length === 0) {
      scope.pending = false;
      return;
    }
    scope.pending = true;
    const o = queue.shift(0);
    load(o).then(function() {
      process();
    })
  };
  
  scope.add = function(s, el, att, onload) {
    // Check the element isn't already in the queue
    for (let a=0; a<queue.length; a++) {
      if (queue[a].elem === el) return;
    }
    queue.push({
      elem: el,
      scope: s,
      attrs: att,
      onload: onload
    });
    
    if (scope.pending) return;
    else process();
  };
  
  angular.element(window).on('scroll resize',process);
  
  return scope;
}])
.directive('lazyLoad', ['$compile', '$interpolate', 'lazyLoadQ', function($compile, $interpolate, lazyLoadQ) {
  return {
    scope: true,
    restrict: 'A',
    compile: function(tElem, tAttrs) {
      const expression = [$interpolate.startSymbol(), 'src', $interpolate.endSymbol()].join('');    
      tElem.attr('data-ng-src', expression);
      tElem.removeAttr('data-lazy-load');
      return function(scope, elem, attrs) {
        $compile(elem)(scope);
        function load(e) {
          if (scope.src)
            angular.element(window).off('resize scroll', load);

          const viewportOffset = elem[0].getBoundingClientRect();
          if (window.innerHeight + window.scrollY >= viewportOffset.top) {
            if (!lazyLoadQ.pending)
              lazyLoadQ.add(scope, elem, attrs, e.type === 'load');
            else
              setTimeout(function() { load(e); },0);
          }
        }
        angular.element(window).on('load scroll resize',load);
      }
    }
  };
}])

Comments