I have the following ng-repeat
that grabs data from a $http.post
call and stores it into $scope.data
.
<div ng-repeat="key in [] | range:data.pages">
<div class="pageBackground" id="page_{{ (key+1) }}" ng-style="{'background-image':'url(/images/{{data.id}}/{{(key+1)}}.png)'}">
<!-- some random stuff here -->
</div>
What normal happens is the .pageBackground
class will load before the background image does on the screen. I'd like nothing to show up until the background-image
is actually loaded but I haven't been able to figure that out.
Does anyone have any suggestions?
I have the following ng-repeat
that grabs data from a $http.post
call and stores it into $scope.data
.
<div ng-repeat="key in [] | range:data.pages">
<div class="pageBackground" id="page_{{ (key+1) }}" ng-style="{'background-image':'url(/images/{{data.id}}/{{(key+1)}}.png)'}">
<!-- some random stuff here -->
</div>
What normal happens is the .pageBackground
class will load before the background image does on the screen. I'd like nothing to show up until the background-image
is actually loaded but I haven't been able to figure that out.
Does anyone have any suggestions?
Share Improve this question asked Jan 26, 2016 at 18:58 bryanbryan 9,36918 gold badges90 silver badges174 bronze badges 2- Have you tried this approach? Easiest Way To Delay Loading of Images in Agular @ StackOverflow – SL8t7 Commented Feb 16, 2016 at 0:27
- Can you create a plnkr that reproduces this problem? It seems to me that @sp00m's answer should work. – Joe Enzminger Commented Feb 16, 2016 at 3:45
8 Answers
Reset to default 5 +25I'm not sure there is a real solution for your problem. A workaround could be to use the Image object, as explained in this answer. For example as a directive:
angular.module("yourModule").directive("showOnceBackgroundLoaded", [function () {
return {
restrict: "A",
scope: false,
link: function (scope, element, attributes) {
element.addClass("ng-hide");
var image = new Image();
image.onload = function () {
// the image must have been cached by the browser, so it should load quickly
scope.$apply(function () {
element.css({ backgroundImage: 'url("' + attributes.showOnceBackgroundLoaded + '")' });
element.removeClass("ng-hide");
});
};
image.src = attributes.showOnceBackgroundLoaded;
}
};
}]);
Use:
<div ng-repeat="key in [] | range:data.pages">
<div class="pageBackground" id="page_{{ (key+1) }}" show-once-background-loaded="/images/{{data.id}}/{{(key+1)}}.png">
<!-- some random stuff here -->
</div>
Look here for a solution:
How can I tell when a CSS background image has loaded? Is an event fired?
what you do is you create an invisible partner element loading the same image. if and only if that image has been loaded (onload event) you show your other element, so for example:
<div ng-repeat="key in [] | range:data.pages" ng-init="_imageLoaded={}">
<div ng-show="_imageLoaded[$index]" class="pageBackground" id="page_{{ (key+1) }}" ng-style="{'background-image':'url(/images/{{data.id}}/{{(key+1)}}.png)'}">
<img ng-show="false" src="/images/{{data.id}}/{{(key+1)}}.png" onload="_imageLoaded[$index] = true;" />
<!-- some random stuff here -->
</div>
You can delay your startup function until the image loads.
var img = new Image();
img.onload = function(){
loadData();
};
img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
Then put an ng-if="imageLoaded"
in the html and set that to true in the loadData
function.
Here is a directive that embeds your image as a background, and waits to show itself until after the image has loaded. You can include variables inside the "mysrc" parameter as needed to generate different images (such as from within an ng-repeat).
angular.module('foo', [])
.directive('myPageBackground', function() {
return {
scope: {
key: '=', // used for ID of the element; if you set the ID externally to the directive you could omit this
mysrc: '=' // used for the URL of the desired background image
},
template: '<div ng-show="showMe" class="pageBackground" id="page_{{key}}" ng-style="{\'background-image\':\'url({{mysrc}})\'}"></div>',
link: function(scope) {
var img = new Image();
img.onload = function() {
scope.showMe = true;
scope.$apply();
};
img.src = scope.mysrc;
}
}
});
.pageBackground {
width: 200px; height: 200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="foo">
<!-- Done with hardcoded values here, just for demo: -->
<div my-page-background key="'1'" mysrc="'http://placehold.it/200x200'"></div>
<div my-page-background key="'2'" mysrc="'http://placehold.it/150x150'"></div>
<div my-page-background key="'3'" mysrc="'http://placehold.it/100x100'"></div>
</div>
If you're always using the same class="pageBackground"
, then you background image is always the same. You can load it in the hidden image, so browser caches it:
<img src="url" style="display:none;"/>
Or preload with javascript on page load:
var img = new Image();
img.src = 'some url';
I believe, that post is triggered with user interaction, which happens definitely after page has been loaded, so the image already sits in browser and it will appear immediately when you apply class="pageBackground"
Hope this helps!
You could use ngSrc directive instead of a div. In addition, you could try to use a tiny lazy loading image library such as ng-lazy-img.
I hope that helps!
Here's a fully-functioning example using the Image object.
function AppCtrl($scope) {
$scope.images = [{
src: 'https://farm4.staticflickr.com/3261/2801924702_ffbdeda927_d.jpg'
}, {
src: 'https://farm9.staticflickr.com/8455/8048926748_1bc624e5c9_d.jpg'
}];
angular.forEach($scope.images, function(image) {
var img = new Image();
img.onload = function() {
$scope.$apply(function() {
image.loadedSrc = image.src;
});
};
img.src = image.src;
});
}
.hasSrc {
color: purple;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app>
<div ng-controller="AppCtrl">
<div ng-repeat="image in images" ng-class="{ hasSrc: !!image.loadedSrc }" style="background-image: url({{image.loadedSrc}})">
<h2>THIS IS SOME TEXT BEING USED</h2>
<p>
This text is being used for illustration purposes only.
</p>
</div>
</div>
</div>
It should be easy enough to adapt this to suit your purposes.
You can take help from angular promises. If the image is loaded as promised render the view else not.
You may already checked this link.
preloading-images-in-angularjs-with-promises
Thanks