How to detect all imges loading finished in AngularJS

Kuan picture Kuan · May 12, 2015 · Viewed 8.2k times · Source

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?

Answer

jad-panda picture jad-panda · May 12, 2015

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.