Angular\'s ng-src keeps previous model until it preloads image internally. I am using different image for the banner on each page, when I switch routes, i change main view,
Having the 2 urls on the directive seems a touch overcomplicated. What I think is better is to write a directive that works like:
<img ng-src="{{bannerUrl}}" spinner-on-load />
And the directive can watch ng-src
and (for example) set visibility:false with a spinner until the image has loaded. So something like:
scope: {
ngSrc: '='
},
link: function(scope, element) {
element.on('load', function() {
// Set visibility: true + remove spinner overlay
});
scope.$watch('ngSrc', function() {
// Set visibility: false + inject temporary spinner overlay
});
}
This way the element behaves very much like a standard img with an ng-src
attribute, just with a bit of extra behaviour bolted on.
http://jsfiddle.net/2CsfZ/47/
A simple solution I've found is to change the url to '//:0' before assigning it's new value
$scope.bannerUrl = 'initial value';
// When we want to change it
$scope.bannerUrl = '//:0'; // remove the previous img so it's not visible while the new one loads
$scope.bannerUrl = scope.preloadedUrl
If anyone is interested this is my final solution: I use twitter bootstrap. So added class of "fade" to all images and just toggling class "in" with directive to fade in and out when image is loaded
angular.module('myApp').directive('imgPreload', ['$rootScope', function($rootScope) {
return {
restrict: 'A',
scope: {
ngSrc: '@'
},
link: function(scope, element, attrs) {
element.on('load', function() {
element.addClass('in');
}).on('error', function() {
//
});
scope.$watch('ngSrc', function(newVal) {
element.removeClass('in');
});
}
};
}]);
<img img-preload class="fade" ng-src="{{imgSrc}}">
Working example: http://ishq.org
Just to share ^^
//css
.media-box{
position: relative;
width:220px;
height: 220px;
overflow: hidden;
}
.media-box div{
position: absolute;
left: 0;
top: 0;
}
.spinner{
position: absolute;
left: 0;
top: 0;
background: #CCC url(./spinner.gif) no-repeat center center;
display: block;
width:220px;
height: 220px;
}
.feed img.spinner-show{
visibility: visible;
}
.feed img.spinner-hide{
visibility: hidden;
}
//html
<div class="media-box">
<div>
<img data-ng-src="{{item.media}}" alt="" title="" data-spinner-on-load>
</div>
</div>
//js
.directive('spinnerOnLoad', function() {
return {
restrict: 'A',
link: function(scope,element){
element.on('load', function() {
element.removeClass('spinner-hide');
element.addClass('spinner-show');
element.parent().find('span').remove();
});
scope.$watch('ngSrc', function() {
element.addClass('spinner-hide');
element.parent().append('<span class="spinner"></span>');
});
}
}
});
images can be preloaded on route change by using image-preloader factory and resolve:
// call REST
return getContent.get().$promise.then(function(response) {
//return response;
// preload images from response
var imageLocations = [
// put image(s) from response to array
response.PostImage.big[0],
];
// check do we have (all) image(s) in array
console.log(imageLocations);
// return when all images are preloaded
return preloader.preloadImages( imageLocations )
.then(function() {
//if it was success
return response;
},
function() {
//if it failed
return response;
});
});
complete tutorial here: https://www.coditty.com/code/angular-preload-images-on-route-change-by-using-resolve
I have this directive which shows a spinner when img-src changes:
<img-with-loading
img-src="{{src}}"
spinner-class="{{spinnerClass}}"
/>
Code here: http://jsfiddle.net/ffabreti/yw74upyr/