4

I want to use ng-repeat to show more then 100 images in a page. Those images are taking significant time in loading and i don't want to show them getting loaded to the users. So, I only want show them after all of them are loaded in the browser.

Is there a way to detect, if all the images are loaded?

jad-panda
  • 2,509
  • 16
  • 22
Kuan
  • 11,149
  • 23
  • 93
  • 201

2 Answers2

11

you can use load event like this.

image.addEventListener('load', function() {
       /* do stuff */ 
});

Angular Directives

Solution for single image

HTML

<div ng-app="myapp">
    <div ng-controller="MyCtrl1">
        <loaded-img src="src"></loaded-img>
        <img ng-src="{{src2}}" />'
    </div>
</div>

JS

var myApp = angular.module('myapp',[]);
myApp
    .controller('MyCtrl1', function ($scope) {
            $scope.src = "http://lorempixel.com/800/200/sports/1/";
            $scope.src2 = "http://lorempixel.com/800/200/sports/2/";
    })
    .directive('loadedImg', function(){
        return {
            restrict: 'E',
            scope: {
                src: '='
            },
            replace: true,
            template: '<img ng-src="{{src}}" class="none"/>',
            link: function(scope, ele, attr){
                ele.on('load', function(){
                    ele.removeClass('none');
                });           
            }
        };
    });

CSS

.none{
    display: none;
}

http://jsfiddle.net/jigardafda/rqkor67a/4/

if you see the jsfiddle demo, you will notice src image is only showing after image is fully loaded whereas in case of src2 you can see image loading.(disable cache to see the difference)

Solution for multiple images

HTML

<div ng-app="myapp">
    <div ng-controller="MyCtrl1">
        <div ng-repeat="imgx in imgpaths" ng-hide="hideall">
            <loaded-img isrc="imgx.path" onloadimg="imgx.callback(imgx)"></loaded-img>
        </div>
    </div>
 </div>

JS

var myApp = angular.module('myapp',[]);
myApp
    .controller('MyCtrl1', function ($scope, $q) {

        var imp = 'http://lorempixel.com/800/300/sports/';

        var deferred;
        var dArr = [];
        var imgpaths = [];

        for(var i = 0; i < 10; i++){
            deferred = $q.defer();
            imgpaths.push({
                path: imp + i,
                callback: deferred.resolve
            });
            dArr.push(deferred.promise);
        }

        $scope.imgpaths = imgpaths;

        $scope.hideall = true;

        $q.all(dArr).then(function(){
            $scope.hideall = false;
            console.log('all loaded')
        });
    })
    .directive('loadedImg', function(){
        return {
            restrict: 'E',
            scope: {
                isrc: '=',
                onloadimg: '&'
            },
            replace: true,
            template: '<img ng-src="{{isrc}}" class="none"/>',
            link: function(scope, ele, attr){
                ele.on('load', function(){
                    console.log(scope.isrc, 'loaded');
                    ele.removeClass('none');
                    scope.onloadimg();
                });           
            }
        };
    });

To detect if all images are loaded,

for each image i generated a deferred object and passed its deferred.resolve as a image onload callback of the directive and then pushed that deferred objects promise in an array. and after that i used $q.all to detect if all those promise are yet resolved or not.

http://jsfiddle.net/jigardafda/rqkor67a/5/

UPDATE: angular way added.

UPDATE: added solution for loading multiple images.

jad-panda
  • 2,509
  • 16
  • 22
  • Thanks, two questions about this: [1] does this load event mean finish loading of single image? [2] If so for[1], How can I detect all load event are triggered? – Kuan May 12 '15 at 18:25
  • you didn't answer..what OP wants..you only thinking about single..what if the images are loaded using ng-repeat – Pankaj Parkar May 12 '15 at 18:54
  • @Kuan, one way is to keep track of all the images status (loaded or not loaded) in a service. and once all images are loaded then service will fire some event to notify. – jad-panda May 12 '15 at 18:59
  • @pankajparkar and Kuan, I have added solution for loading multiple images, check updated answer. – jad-panda May 12 '15 at 19:39
  • @jad-panda appreciated..+1 for your answer – Pankaj Parkar May 12 '15 at 20:18
  • @jad-panda Thanks, I will try this directive. BTW, could you show me some great tutorial links to learn how t use $q? – Kuan May 13 '15 at 16:20
  • @Kuan see this article its good. https://lostechies.com/gabrielschenker/2014/02/04/angularjspart-11-promises/ – jad-panda May 13 '15 at 20:01
  • @jad-panda Hi, Jad, there is another question related to this, which is: for the first time, when I assign a url to a ng-src, the img can trigger the on("load") event, but the second time, if I give it the same url, the load event will not triggered, I wonder how can I still trigger its load event? – Kuan May 14 '15 at 16:10
  • @Kuan, Do you mean you want to change the value of `imgpaths` variable dynamically every time ? – jad-panda May 14 '15 at 17:15
  • @jad-panda I post my question here. http://stackoverflow.com/questions/30242928/prevent-loading-image-from-cache – Kuan May 14 '15 at 17:16
  • This is brilliant code, thank you @jad-panda for sharing it. I do have a slight issue with it; I'm trying to manipulate some of the images as they are being downloaded (which I manage to do quite easily in the directive load response) but for some reason, I get the 'all loaded' log from the array, somewhere towards all images being downloaded. Not at the very end! http://148.88.67.145/projects/postcards/images/12.jpg loaded http://148.88.67.145/projects/postcards/images/10.jpg loaded all loaded http://148.88.67.145/projects/postcards/images/10a.jpg loaded – Adrian Sep 19 '16 at 10:39
  • @jad-panda I can sorted it out with a timeout, but was wondering why this happens. Thank you! – Adrian Sep 19 '16 at 10:46
-1

Check if all images are loaded

jQuery.fn.extend({
  imagesLoaded: function( callback ) {
    var i, c = true, t = this, l = t.length;
    for ( i = 0; i < l; i++ ) {
      if (this[i].tagName === "IMG") {
        c = (c && this[i].complete && this[i].height !== 0);
      }
    }
    if (c) {
      if (typeof callback === "function") { callback(); }
    } else {
      setTimeout(function(){
        jQuery(t).imagesLoaded( callback );
      }, 200);
    }
  }
});
  • Callback occurs when all images are loaded
  • image load errors are ignored (complete will be true)
  • Use: $('.wrap img').imagesLoaded(function(){ alert('all images loaded'); });

Note : this code worked for me, Source :

http://wowmotty.blogspot.in/2011/12/all-images-loaded-imagesloaded.html

Rahul Sagore
  • 1,588
  • 2
  • 26
  • 47