10

The idea is to show a low-res version of an image before the real high-resolution image has been downloaded, ideally using an img tag.

<img lowres="http://localhost/low-res-image.jpg" ng-src="http://localhost/low-res-image.jpg">

Low-res image would be visible first, and be replaced with high-res image after it has been downloaded. How can this be done? Is it possible to edit img.src attribute, or should something else (e.g. a wrapper div with background, or another temporary div) be created?

Mika Vatanen
  • 3,782
  • 1
  • 28
  • 33

6 Answers6

23

You'd probably want to create a directive, I'd actually have hires as the attribute, so that by default it starts with lores.

JS:

app.directive('hires', function() {
  return {
    restrict: 'A',
    scope: { hires: '@' },
    link: function(scope, element, attrs) {
        element.one('load', function() {
            element.attr('src', scope.hires);
        });
    }
  };
});

HTML:

<img hires="http://localhost/hi-res-image.jpg" src="http://localhost/low-res-image.jpg" />
dave
  • 62,300
  • 5
  • 72
  • 93
  • 5
    Brilliantly simple solution! However, ran into a problem when the src was already cached by browser: scope.hires was sometimes empty. Solved by: http://jsfiddle.net/BgDjZ/1/ – Mika Vatanen Apr 01 '14 at 19:15
  • The above answer will cause infinite load loop. See below. – VicJ May 27 '15 at 12:59
  • 1
    Good call, fixed to prevent infinite loop – dave May 27 '15 at 16:18
  • @dave thanks, its working, but how can i `change image later dynamically` by updating `hires url` – Saqueib Jan 09 '16 at 13:35
  • my page has two tab selection. This method works well when I access the page for the first time, but when I switch to another tab, it doesn't work. seems doesn't fire the on load method for tab select? – Carrie May 11 '16 at 18:55
  • Also, I `console.log('load fired');` in the `element.on('load',function(){};`, I noticed it's fired 8 times when there's actually 4 images loading. Don't know why. It's always fried doubled times. – Carrie May 11 '16 at 19:10
  • It needs to be .one not .on otherwise it fires again when the hires version loads – dave May 11 '16 at 19:13
  • @dave It's a typo, I used one, it's still loading double times. And doesn't work for tab selection or scrolling down to load more images. – Carrie May 11 '16 at 19:40
  • @dave I actually asked a question here: http://stackoverflow.com/questions/37171842/show-placeholder-image-before-real-image-loaded-doesnt-work-for-tab-selection-a If you don't mind to take a look. Thanks a lot. – Carrie May 11 '16 at 19:41
  • Does this set the element's src to scope.hires when the lowres image has finished loading? – Jamie Carruthers Jun 01 '16 at 13:17
  • 2
    @JamieCarruthers yes it does – dave Jun 01 '16 at 16:52
11

Because ng-src is going to replace whatever is in src why not use both?

<img src="img/placeholder.jpg" ng-src="{{actualone.img}} "  height="150px " width="300px ">

Use normal src for your placeholder. It will get replaced one the image for ng-src is ready.

Kyle Pennell
  • 5,747
  • 4
  • 52
  • 75
  • 3
    This doesn't work. You can see the actual image loading process on the page, section by section. – Carrie May 09 '16 at 16:02
4

The above answer is misleading and here's why. You need to unbind the load event as it will cause infinite load loop on desktop and mobile browsers if you run it in an ng-repeat directive each src replacement will cause new load event to fire and therefore replacement of image etc. The above answer caused my app to break not only performance wise but also caused crashes on mobile devices until I added the unbind.

.directive('imageloaded', function () {
return {
  restrict: 'A',
  scope:{imageloaded:'@'},
  link: function postLink(scope, element, attrs) {
    element.bind('load', function() {
        //console.log('load fired') <- just console log it and comment the unbind and you will see the 10000s of console logs.
        element.attr('src', scope.imageloaded);
        element.unbind('load');
    });
  }
};

});

VicJ
  • 121
  • 6
1

Simple examle. try this, without using directives
HTML

<img  ng-src="{{loading.image_url}}" >

Javascript

//within controller
    $scope.loading.image_url = 'path_to_loading_image';
    var loaded_img = 'path_to_loaded_image';
    $http.get(loaded_img).then(function() {
        $scope.loading.image_url = loaded_img;
    }, function() {
        console.log('something went wrong!');
    });
codelearner
  • 458
  • 5
  • 26
0

You can change the src attribute of image after it is loaded. you need to bind load event to image to find out when the image is loaded.

See this page Detect image load by jQuery

You can use a directive to set the initial src attribute and bind the load event to change src to main image.

Community
  • 1
  • 1
Alborz
  • 6,843
  • 3
  • 22
  • 37
0

I found this simple solution

<img ng-src="{{::val.image}}"  width="400" height="300" alt="" onerror="this.src='img/logo-sm.png'"  src="img/logo-sm.png">

Hope it helps somenone

oguz ismail
  • 1
  • 16
  • 47
  • 69
OneGhana
  • 119
  • 5