Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

if a ngSrc path resolves to a 404, is there a way to fallback to a default?

It's a pretty simple directive to watch for an error loading an image and to replace the src. (Plunker)

Html:

<img ng-src="smiley.png" err-src="http://google.com/favicon.ico" />

Javascript:

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

app.directive('errSrc', function() {
  return {
    link: function(scope, element, attrs) {
      element.bind('error', function() {
        if (attrs.src != attrs.errSrc) {
          attrs.$set('src', attrs.errSrc);
        }
      });
    }
  }
});

If you want to display the error image when ngSrc is blank you can add this (Plunker):

attrs.$observe('ngSrc', function(value) {
  if (!value && attrs.errSrc) {
    attrs.$set('src', attrs.errSrc);
  }
});

The problem is that ngSrc doesn't update the src attribute if the value is blank.


Little late to the party, though I came up with a solution to more or less the same issue in a system I'm building.

My idea was, though, to handle EVERY image img tag globally.

I didn't want to have to pepper my HTML with unnecessary directives, such as the err-src ones shown here. Quite often, especially with dynamic images, you won't know if it's missing until its too late. Adding extra directives on the off-chance an image is missing seems overkill to me.

Instead, I extend the existing img tag - which, really, is what Angular directives are all about.

So - this is what I came up with.

Note: This requires the full JQuery library to be present and not just the JQlite Angular ships with because we're using .error()

You can see it in action at this Plunker

The directive looks pretty much like this:

app.directive('img', function () {
    return {
        restrict: 'E',        
        link: function (scope, element, attrs) {     
            // show an image-missing image
            element.error(function () {
                var w = element.width();
                var h = element.height();
                // using 20 here because it seems even a missing image will have ~18px width 
                // after this error function has been called
                if (w <= 20) { w = 100; }
                if (h <= 20) { h = 100; }
                var url = 'http://placehold.it/' + w + 'x' + h + '/cccccc/ffffff&text=Oh No!';
                element.prop('src', url);
                element.css('border', 'double 3px #cccccc');
            });
        }
    }
});

When an error occurs (which will be because the image doesn't exist or is unreachable etc) we capture and react. You can attempt to get the image sizes too - if they were present on the image/style in the first place. If not, then set yourself a default.

This example is using placehold.it for an image to show instead.

Now EVERY image, regardless of using src or ng-src has itself covered in case nothing loads up...


To expand Jason solution to catch both cases of a loading error or an empty source string, we can just add a watch.

Html:

<img ng-src="smiley.png" err-src="http://google.com/favicon.ico" />

Javascript:

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

app.directive('errSrc', function() {
  return {
    link: function(scope, element, attrs) {

      var watcher = scope.$watch(function() {
          return attrs['ngSrc'];
        }, function (value) {
          if (!value) {
            element.attr('src', attrs.errSrc);  
          }
      });

      element.bind('error', function() {
        element.attr('src', attrs.errSrc);
      });

      //unsubscribe on success
      element.bind('load', watcher);

    }
  }
});

App.directive('checkImage', function ($q) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            attrs.$observe('ngSrc', function (ngSrc) {
                var deferred = $q.defer();
                var image = new Image();
                image.onerror = function () {
                    deferred.resolve(false);
                    element.attr('src', BASE_URL + '/assets/images/default_photo.png'); // set default image
                };
                image.onload = function () {
                    deferred.resolve(true);
                };
                image.src = ngSrc;
                return deferred.promise;
            });
        }
    };
});

in HTML :

<img class="img-circle" check-image ng-src="{{item.profileImg}}" />

If image is 404 or image is null empty whatever there is no need for directives you can simply use ng-src filter like this :)

<img ng-src="{{ p.image || 'img/no-image.png' }}" />

I use something like this, but it assumes that team.logo is valid. It forces default if "team.logo" isn't set or is empty.

<img ng-if="team.logo" ng-src="https://api.example.com/images/{{team.logo}}">
<img ng-hide="team.logo" ng-src="img/default.png">

You don't need angular for that, or even CSS or JS. If you want, you can wrap this answer (linked) in a simple directive to make it simpler, like or something, but it's a pretty simple process... just wrap it in an object tag...

How to hide image broken Icon using only CSS/HTML (without js)