So there's no issue with this code functionality itself. I have something like this:
<div>
<div><img id="imageToChange" src="/path/image.png" /></div>
<div id="textToChange">Text</div>
</div>
I have another part of my code, that changes the image src/text with jQuery.
function changeImage() {
$('#imageToChange').prop('src', '/path/image2.png');
$('#textToChange').html('New Text');
}
As you may expect, this works exactly as I expect it to. But with 1 quirk.
In all the main browsers (chrome/FF/IE). The image takes a long time to change.
So for example, when I call changeImage(), the text will change instantly, but the image may not change until 1-2 seconds later. (Not large images by any stretch, about ~6KB, and local)
I haven't found anyone else really complaining about it, but what I'm wondering is if there's any way to speed up the changing of the image src? Perhaps a better way to do it?
This is jquery 1.8.0 as well.
Thanks
I have seen this behavior before. The delay is caused by the image not being cached and the subsequent load time. The only solutions I know of:
Preload your images with JavaScript Image objects.
Handle the load event on the image and update the text after the image as loaded. Note jQuery lists some issues to watch out for:
Caveats of the load event when used with images
A common challenge developers attempt to solve using the .load()
shortcut is to execute a function when an image (or collection of
images) have completely loaded. There are several known caveats with
this that should be noted. These are:
It doesn't work consistently nor reliably cross-browser
It doesn't fire correctly in WebKit if the image src is set to the same src as before
It doesn't correctly bubble up the DOM tree
Can cease to fire for images that already live in the browser's cache
http://api.jquery.com/load-event/
You may want to try altering the attribute using the jquery .attr function. If I recall correctly the src tag of an image is an attribute not a property. Although both .prop and .attr do relatively the same function, to ensure consistent behavior between browsers you may want to use the .attr tag instead.
$('#imageToChange').attr('src', '/path/image2.png');
As far as the delay goes, this could be due to the size of the image. The browser has to make a GET request to the server for the image and then paint the DOM with it. If the image is large, it could cause a time lapse between when the code changes the source and when the new image is properly written to the DOM. If the image is large, you may want to consider scaling it down or optimizing it for web use.
Hope this helps.
You can pre-load the image using the Javascript Image object.
In the head of your document put
<script type="text/javascript">
img2 = new Image();
img2.src = "/path/image2.png";
</script>
when you change the src of the image you fetch another image file. it makes an HTTP request for the new image, so it needs to load before showing it. could this be it?
btw, for this reason you can pre-load the image with js. either add
<img src="path/to/image.jpg" style="display: none" />
to your html or using JS
var im = new Image(1,1);
im.src = "path/to/image.jpg";
this way the image will be cached
It's the delay of network. Try this:
<div>
<div><img id="imageToChange" src="/path/image.png" /></div>
<div id="textToChange">Text</div>
</div>
<img src='/path/image2.png' style='display:none'>
it is likely the load time of your images. if this is the case, loading the image the first time should be the only slow one. a follow up load, after changing the image to something else, would be fast.
$('#imageToChange').prop('src', '/path/image1.png');
//slow, need to fetch image
$('#imageToChange').prop('src', '/path/image2.png');
//slow, need to fetch image
$('#imageToChange').prop('src', '/path/image1.png');
//fast, it already has this image
As a solution, you could try preloading your images. Or, better yet, use css sprites.
Related
HTML:
<div id="rb-hero" class="rb-hero uk-block uk-flex uk-flex-middle uk-contrast arrowed">
<ul class="uk-slideshow uk-slideshow-fullscreen" id="biggie_slides" data-uk-slideshow="{pauseOnHover: false, autoplay:true}">
<li><img src="{theUrlMedium}" alt="{theAltText}" srcset="{theUrlSmall} 750w, {theUrlMedium} 1200w, {theUrlLarge} 2000w, {theUrlXL} 3000w" ></li>
</ul>
</div>
jQuery:
$('#rb-hero li img').each(function() {
var theSrc = $(this).prop('currentSrc');
// console.log(theSrc);
$(this).prev('div').attr('style', 'background-image: url( '+theSrc+' )');
});
UIKit provides a slideshow function, and I have it in use and it works just fine. The way it works is to use each image slide's src as an inline background-image style attribute on a dynamically-created div. All works fine.
The problem is that UIKit does not use the appropriately-sized image from the provided srcset (which is also working correctly per the currentSrc info in devtools), it simply grabs the fallback img src and thus a pretty high-res image when on mobile.
I'm trying to loop through the elements and replace the inline style's background-imagesource with the currentSrc, but I'm hitting a wall.
The each() method is doing its magic and the console logs the smaller-sized image based on the appropriate srcset source at smaller screens, but the setting of the inline style is going nowhere.
So I'm missing something, and it's probably going to be obvious and glaring but in addition to sleep I need an assist.
Thanks.
Edit: Updated code to a better working place and now only the final bit's not working.
I edited my first answer as it was complete nonsense.
I did some testing with your code and two differently sized images and found that it actually works, but only if certain conditions are met:
I noticed that the browser won't load a smaller sized image from the srcset if there's a larger one already in the cache. I guess it's meant to work this way, but you'll have to keep that in mind and clear the browser cache while testing.
But if you first resize your browser window, then clear the cache and reload the page, the smaller images actually are being loaded and set as background images. I also had to wrap your code in a setTimeout function, otherwise even the console.log was empty and nothing happened. This wasn't necessary with an enlarged browser window (probably because it loaded the image straight from the src tag so there was no delay).
Another problem is that uikit will have set the background image from the src tag and the browser will have loaded it before you set the image url from the srcset, so you'll load both files (which is even worse than only loading the large one on a small screen).
The cleanest and easiest solution would be to modify uikit's slideshow component. They only had to change the part where the image url is read from attr('src') to prop('currentSrc').
I am dynamically changing images with jQuery using $('img').attr('src','newUrl');
Doing so, the image is only displayed when entirely loaded.
My connection is slow, so I would like the image to directly display and see it getting progressively loaded, the same way images “appear” when I arrive on any page on the web (whether from top to bottom, or from blurry to sharp depending on the compression algorithm of the image).
I want to do this with javascript, jQuery, or any simpler alternative.
(I know how to display a progress bar, or a "loading…" text while the image loads, that's not what I'm looking for)
Here's a fiddle if you want to update.
I've found a way to do that, what you want. Don't use attr("src",) from jquery, remove and add the hole img element with html(), so you trigger the browser to load the image source and the browser displays the image while loading (tested in chrome).
Html:
<p><button>change image source</button></p>
<div>
<img src="http://xxxxx">
</div>
Script:
var newImg = '<img src="http://yyyyyy">';
$('button').click(function(){
$('div').html(newImg);
});
Here is your updated fiddle: http://jsfiddle.net/jxwv52u7/1/
I hope it helps.
Based on some testing I did about a year ago, I found no reliable way to get a load event when changing the .src of an image from one value to another. As such, I had to resort to loading a new image and replacing the one I had with the new one when the new image was loaded. That code has been running successfully in several hundred web sites (it's used by a slideshow) for about a year now so I know it works.
If you set the load handler BEFORE you set the .src property on a new image, you will reliably get the load event. Here's some code I wrote just earlier today for capturing the load event: jQuery: How to check when all images in an array are loaded?.
This code that attaches the event handler BEFORE settings the .src works for me in the modern browsers I've tried it in (I didn't test older browsers):
$("img").one("load", function() {
// image loaded here
}).attr("src", url);
You can see it work here:DEMO and you can test any browsers you want using that jsFiddle. Just click on the image to cause it to load a new image. It cycles through three different images (setting .src each time), loading two of them uniquely every time (never from the cache) and one from the cache in order to test both cases. It outputs a msg to the screen whenever the .load handler is called so you can see if it's called.
Is it possible to detect - using jQuery or pure DOM manipulation / events - when an image that was injected into the document has fully loaded? For example, a script needs to replace one image with another. If it just changes the src attribute, the user will see an image disappear briefly (or not so briefly, depending on their connection). So, a better option would be to create a new image element in some hidden place (or, if cross-platformly possible, out of DOM entirely) and switch images only when the new one is ready. Can this be done?
EDIT: It might be a separate question, but still... Is there also a way to detect when an image has failed to load?
You can use image.onload = function(){<...>};
Image is the actual image you want to get the load of.
<img src='...' id='image'>
In order to check if the image finished loading do the following->
document.getElementById('image').onload = function(){<...>}
or
document.getElementById('image').addEventListener('load',function(){<...>},false);
If you want to check if the image failed to load do this->
document.getElementById('image').onerror = function(){<...>}
or
document.getElementById('image').addEventListener('error',function(){<...>},false);
Note
.addEventListener method won't work in IE8. If you are planning on supporting it I can edit my answer.
yes you can do that by using the .load() event.
like,
$('#img1').load(function(){ alert('loaded'); });
the alert will be displayed when the resources for that particular selector has loaded fully.
The .load() event does not always work as expected and is prone to fail under different circumstances. For broadest browser support I suggest to use DeSandro's imagesLoaded (which I find to be best practice anyway): https://github.com/desandro/imagesloaded
I've got an image that is loaded when the site is called.
<img id="some_Image" src="some_source">
Now I want to reuse that image and NOT request it again from "some_source". (Because it has to be computed and I do not want to recalculate it). I want that image later to be displayed in some JQuery dialog. I know the existance of append and prepend functions, but reading the documentation it seems like I have to insert a whole image tag as an argument, which results in requesting the image again. (if the browser doesn't cache the image)
have a look at the jQuery clone
it is supposed to work with images as well, if the image has been loaded by the browser its supposed to reuse it.
EDIT:
$( "#some_image" ).clone().appendTo( "#some_div" );
By default, all browsers cache as much as they can (js, css, images). This way, the moment your image is loaded you can create a new <img> tag with the same source path and the browser will use its local cached file.
I've got a page containing a lot of images, which are initially hidden from view as I'm using tabbed divs (ie. hiding some divs using CSS display:none).
Therefore, when then page loads, it takes ages to load all of the images, which looks like the page is slow (as the loading bar on the browser doesn't complete for 10+ seconds).
I would like a way of not loading images until they are visible on the page.
I've played around with jQuery LazyLoad, however this only seems to load images when scrolling the browser (which doesn't work for tabbed divs).
Therefore, is there a way of changing LazyLoad to work like this, or is there a better way of doing this?
Thanks!
Maybe jQuery Tabs could do what you need, with ajax call on tabs...
How do you display your hidden divs?
One plan of attack:
Instead of putting the image URL in the src attribute of the img tag, put it somewhere else (e.g. a hidden span with a particular class above it) and when showing the div, iterate through all the img tags and set the src to the URL it should have had.
As a method it's definitely got some downsides.
If you're using (or can use) the HTML5 doctype, you can use the "data-" prefix for tag attributes:
<img src="" data-src="/path/to/image" style="display: none" />
And then you can use Javascript to fill the src with the data-src:
$(SELECTOR).attr("src", $(SELECTOR).attr("data-src"));
If your only goal is to 'hide' the progress bar which is taking so long due to the large number of images, I'd go for some kind of AJAX solution, since that way the progress bar is not 'used'. It does introduce more complexity in the way you want to load your HTML elements (and possibly when).
I personally don't like using HTML attributes for anything other than their original purpose, so storing the path in another attribute and switching when needed would not be my first option. Instead, I'd try to create a JavaScript array (id => path) and update the separate HTML IMG elements when needed.
Good luck! ;)
I have tried that lately and have to say that this is not possible with js anymore. Maybe it has never been...
Projects like lazyload have always proclaimed that they would stop all images from loading on startup, but you can see in firebug that this does not work. The images are even loaded twice, on domready and when you start scrolling...
Your only choices would be ajax on the on hand or doing something like this:
<img src="transparent.gif" alt="" rel="real image source" />
and then switch attributes when the divs become visible, so the image starts loading.
This works fine as well at least if you don't need google indexing them.
Hope that helps! :)
Edit: Hm, why did I get a -1 when I was just givin an answer? Just have a look at pages with lazyload and enable firebug and then scroll the page. It was even said here on stackoverflow and in the comments for the lazyload plugin that this is the only solution at the moment ... :(
I was unaware of this previously, but LazyLoad does support triggering from events:
http://www.appelsiini.net/projects/lazyload
If anyone needs a hand on how I did this, let me know!