angular img with loading spinner

by ffabreti

HTML

<p> open Chrome Dev-Tools and set to mobile device with slow network (ex: Regular 3G) </p>
<div ng-controller="c">
    <img-with-loading 
        img-src="{{src}}" 
        spinner-class="{{spinnerClass}}">
    </img-with-loading>
</div>

CSS

.background-spinner {
    background-repeat: no-repeat;
    background-position: center center;
    background-image: url('https://www.yugma.com/images/loading-animation-7.gif')
}

JavaScript

var app = angular.module('app', []);

app.directive('imgWithLoading', function () {
    return {
        restrict: 'E',
        template: '<div/>',
        transclude: false,
        replace: true,
        scope: {
            imgSrc: '@'
        },
        link: function (scope, element, attrs) {
            console.log('imgWithLoading init: ' + scope.imgSrc);
            var img = angular.element(new Image());

            var unbind1 = img.on('load', function (evt) {
                console.log('image loaded: ' + img.attr('src'));
                stopLoadingCSS( );
            });
            var unbind2 = img.on('error', function(evt) {
                console.log('imgWithLoading error Loading ' + scope.imgSrc);
                element.removeClass(attrs.spinnerClass);
            });
            //only define src here, after binding events
            //notice src is retrieve from attrs because scope.imgSrc may be undefined yet
            img.attr('src', attrs.imgSrc);
            startLoadingCSS( );
            element.append(img);

            //watch for changes
            var unbind3 = scope.$watch('imgSrc', function(newVal, oldVal) {
                if ( newVal===img.attr('src') ) return;
                startLoadingCSS( );
                img.attr('src', newVal);
                console.log('imgWithLoading: imgSrc mudou: ' + newVal );
                console.log('imgWithLoading: imgSrc antigo: ' + oldVal );
            });

            scope.$on('destroy', function() {
                console.log('imgWithLoading: unbinding...');
                unbind1(); unbind2(); unbind3(); });

            // ------- LOCAL FUNCTIONS --------------------------------
            function startLoadingCSS( ) {
                img.css({visibility: 'hidden'});
                element.addClass(attrs.spinnerClass);
            }
            function stopLoadingCSS( ) {
                img.css({visibility: 'visible'});
               ...