Deferred (lazy) loading of background images? - javascript

I'm using a simple script to cause a deferred loading of all images on a page; the path for the image sources is contained in a data-src attribute and then put into the actual srcattribute of the img tag(s). Pretty much how most (?) implementations of the lazy loading method work.
Here's the script:
[].forEach.call(document.querySelectorAll('img[data-src]'), function(img) {
img.setAttribute('src', img.getAttribute('data-src'));
img.onload = function() {
img.removeAttribute('data-src');
};
});
I would like to use the same script for deferred loading of background images as well. How do I have to change it so that the data-src attribute ends up in the url-value of a div's background-image-property?
I tried the following with no results, because the script doesn't recognise background-image as a property:
[].forEach.call(document.querySelectorAll('div[data-src]'), function(div) {
div.setAttribute('background-image', div.getAttribute('data-src'));
div.onload = function() {
div.removeAttribute('data-src');
};
});

Problem may be with the background image as an attribute. Have you tried setting the style with the background image?
[].forEach.call(document.querySelectorAll('div[data-src]'), function(div) {
div.setAttribute("style","background-image: url(" + div.getAttribute('data-src') + ");");
div.onload = function() {
div.removeAttribute('data-src');
};
});

[].forEach.call(document.querySelectorAll('div[data-src]'), function(div) {
div.style.backgroundImage="url('" + div.getAttribute('data-src') + "')";
div.onload = function() {
div.removeAttribute('data-src');
};
});
Try this

Related

show alternate image if img src is not found - knockout

I have this piece of code.
<img data-bind="attr: {src: 'imagePath'}, style: { 'background-image': 'url('imagePath')' }" class="img-responsive">
The problem is it is showing two images. One is the image coming from src and other one coming from background image. My goal was to enable the background image when the src image is not available.
What you can do is create a custom binding, let's call it safeSrc.
In this binding, you listen to the load and error events of your image - rendering your image if it's loaded successfully and rendering a fallback if it is not.
In practice, it could look like the following:
ko.bindingHandlers.safeSrc = {
update: function(element, valueAccessor) {
var options = valueAccessor();
var src = ko.unwrap(options.src);
$('<img />').attr('src', src).on('load', function() {
$(element).attr('src', src);
}).on('error', function() {
$(element).attr('src', ko.unwrap(options.fallback));
});
}
};
And then, you can apply the binding like this:
<img alt="Foo" data-bind="safeSrc: {src: imageObservable, fallback: 'https://example.com/fallback.png'}" />
Note that this presumes you're using jQuery - but you can easily rewrite the event listener.
Finally, I would also like to say that you should be rendering a different src instead of the background image - unless you have a specific reason to require one?
Either way, you can simply change the line $(element).attr('src', ko.unwrap(options.fallback)); to $(element).css('background-image', 'url(' + ko.unwrap(options.fallback) + ')');.
JS Fiddle Demo
Here, you can see it all in action: https://jsfiddle.net/13vkutkv/2/
(EDIT: I replaced the cheeky hotlink to the Knockout JS logo with Placehold.it)
P.S.: Depending on how you wish to interact with the element in future (interacting with/updating the binding), you may wish to use applyBindingsToNode (i.e. the Knockout-way), rather than manipulating the src attribute directly on the DOM element.
To show alternate image if img src is not found make alternate image link in your server logic and use only src: 'imagePath' in your front-end
Or if it is important to do it in front-end, you should look at this post:
Display alternate image
I always check my images with a deferred object to be sure they will load. This is using the jquery deferred method, but you could use any deferred library. I coded this from memory, so there may be some errors.
<img data-bind="attr: {src: $root.imagePath()}, style: { 'background-image': 'url('imagePath')' }" class="img-responsive">
var myController = function()
{
var self = this;
this.imagePath = ko.observable('myPath.png'); // Make the image url an observable
var getImagePath = function(path)
{
var imagePath = this.imagePath();
isLoaded(imagePath).done(function(result)
{
// The image will load fine, do nothing.
}).fail(function(e)
{
self.imagePath('defaultImageOnFail.png'); // replace the image if it fails to load
});
};
getImagePath();
};
var isLoaded = function(img)
{
var deferred = new $.Deferred();
var imgObj = $("<img src='"+img+"'/>");
if(imgObj.height > 0 || imgObj.width > 0)
{
deferred.resolve(true);
}
else
{
imgObj.on("load", function(e)
{
deferred.resolve(true);
});
imgObj.on("error", function(e)
{
console.info("VoteScreenController.isLoaded URL error");
deferred.reject();
});
}
return deferred.promise();
};

Is this an efficient way to display an image using jQuery

This code works, but is it an efficient way to go about displaying an image once it has been loaded?
LightBoxNamespace.SetupLightBox = function(path, lightBox) {
// Create a new image.
var image = new Image();
// The onload function must come before we set the image's src, see link for explanation.
// http://www.thefutureoftheweb.com/blog/image-onload-isnt-being-called.
// Anonymous function set to onload event, to make sure we only proceed if the image has been loaded.
image.onload = function () {
if ($('#image').length) {
$('#image').attr('src', path); // If the element already exists, change the src to our loaded image.
}
else {
$('<img id="image" alt="">').attr('src', path).insertAfter('#close'); // If the element does not exist, insert the full image html into the lightbox.
}
LightBoxNamespace.CentreBoxInViewport(lightBox);
LightBoxNamespace.ShowOverlay(lightBox);
};
// Set the src, and show the image.
image.src = path;
};
var img = $('<img>');
img.load(function(){alert("image loaded!")});
img.attr('src', "url");
if (!! img) img.appendTo('#close');
http://jsfiddle.net/W57QR/4/
"The jQuery way":
var $img = $('<img/>').prop({ src: path });
$img.load(function() {
console.log('image loaded correctly');
$(this).insertAfter('#close');
}).error(function() {
console.log('error loading image');
});

Checking if an image is missing from folder in javascript

I am making a small slide show application to show images inside an html.
The name of images are something like:
"MOD01_001.jpg"
"MOD01_002.jpg"
"MOD01_004.jpg" and so for...
Sometimes one or more images is missing and the previous images still is in the cache, so I can't check if the new image was loaded checking for the width/height properties.
What can I do to check if an images are missing from the list (I know I can't access the file info from inside client browser).
TIA
This loads them all in, so it could be really terrible:
var images = ['MOD01_001.jpg','MOD01_002.jpg','MOD01_003.jpg'];
for (i in images) {
checkIfImageExists(images[i]);
}
function checkIfImageExists(image_path) {
var img = new Image();
img.onerror = function(){
console.log('Could not load image: ' + img.src);
}
img.onload = function(){
console.log('Loaded image: ' + img.src);
}
img.src = image_path;
}

JavaScript/jQuery: Running DOM commands *after* img.onload commands

I need to get the width & height of a CSS background image and inject it into document.ready javascript. Something like:
$(document).ready(function(){
img = new Image();
img.src = "images/tester.jpg";
$('body').css('background', 'url(' + img.src + ')');
$('body').css('background-size', img.width + 'px' + img.height + 'px');
});
The problem is, the image width and height aren't loaded in at the time of document.ready, so the values are blank. (They're accessible from console, but not before).
img.onload = function() { ... } retrieves the width and height, but DOM $(element) calls aren't accessible from within img.onload.
In short, I'm a little rusty on my javascript, and can't figure out how to sync image params into the DOM. Any help appreciated
EDIT: jQuery version is 1.4.4, cannot be updated.
You could use $.holdReady() to prevent jQuery's ready method from firing until all of your images have loaded. At that point, their width's and height's would be immediately available.
Star by calling $.holdReady(true). Within the onload method of each image, check to see how many images have been loaded all together, and if that matches the number of expected images, you can $.holdReady(false) to fire the ready event.
If you don't have access to $.holdReady(), you could simply wait to spit out your HTML until all of the images have loaded by still calling a function:
var images = { 'loaded': 0,
'images': [
"http://placekitten.com/500/500",
"http://placekitten.com/450/450",
"http://placekitten.com/400/400",
"http://placekitten.com/350/340",
"http://placekitten.com/300/300",
"http://placekitten.com/250/250",
"http://placekitten.com/200/200",
"http://placekitten.com/150/150",
"http://placekitten.com/100/100"
]};
function outputMarkup() {
if ( ++images.loaded === images.images.length ) {
/* Draw HTML with Image Widths */
}
}
for ( var i = 0; i < images.images.length; i++ ) {
var img = new Image();
img.onload = function(){
outputMarkup();
};
img.src = images.images[i];
}

JS wait for CSS background image to load

It's easy to keep javascript waiting for some images to load if those are classic HTML images.
But I can't figure how to do the same if the image is loaded as a CSS backuground-image!
Is it possible?
The jQuery .load() method doesn't seem to apply.. and I'm short of ideas
It looks for elements with src attribute or backgroundImage css property and calls an action function when theirs images loaded.
/**
* Load and wait for loading images.
*/
function loadImages(images, action){
var loaded_images = 0;
var bad_tags = 0;
$(images).each(function() {
//alert($(this).get(0).tagName+" "+$(this).attr("id")+" "+$(this).css("display"));
var image = new Image();
var src = $(this).attr("src");
var backgroundImage = $(this).css("backgroundImage");
// Search for css background style
if(src == undefined && backgroundImage != "none"){
var pattern = /url\("{0,1}([^"]*)"{0,1}\)/;
src = pattern.exec(backgroundImage)[1];
}else{
bad_tags++;
}
// Load images
$(image).load(function() {
loaded_images++;
if(loaded_images == ($(images).length - bad_tags))
action();
})
.attr("src", src);
});
}
One alternate approach would be to fetch the image data via AJAX as a base64 encoded png and apply it to the element's background-image property.
For example:
$.get('/getmyimage', function(data) {
// data contains base64 encoded image
// for ex: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==
$('#yourElement').css('background-image', 'url("' + data + '")');
});
You will also need a server side script that reads the image, converts it into base64 encoded png (and cache it maybe) and return the same.
Try this one...
Its a jQuery-Plugin which gives you control to wait for images to be loaded
Project-Home
Thread # SO
Official way to ask jQuery wait for all images to load before executing something
Answer # SO
(ShortLink)
this is untested code but try this:
$(document).ready(
function()
{
var imgSrc = $('theTargerElement').css('background-image');
var imgTag = $('<img>').attr('src',imgSrc).appendTo( 'body' );
}
);
$(document)
.load(
function()
{
// do stuff
}
);

Categories

Resources