Hello Stack Overflow community, recently, I've been working on a quick image display using jQuery. It has a list of possible images that can be picked and displayed at random. The issue is, after the page has finished loading, jQuery ceases to detect image load errors for if the image is invalid.
My current method of finding and fixing errors is as follows:
$('img').error(function() {
$(this).attr('src',getImgUrl());
});
This, in normal circumstances such as the page being loaded, picks a valid image, even if multiple invalid images are specified in a row. However, after the page is finished loading, if an invalid image is picked, and fails to load, this function is not even called. Strangely enough though, if I add an onerror attribute to all images, they are always called from the onerror no matter if the page was freshly loaded or not, so why is jQuery having this issue? Any help is appreciated, thanks.
UPDATE:
It also appears this is happening to other jQuery functions as well, such as click.
UPDATE:
It would appear to be an issue with jQuery recognizing new elements on a page, such as newly created images.
UPDATE for those asking getImageUrl:
function getImgUrl()
{
var text = (Math.round(Math.random() * 3)).toString();
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for(var i=0; i < 4; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return '/' + text;
}
All this does is pick a random URL, which matches occasionally to an image on my web-server that has many many images.
It would appear that jQuery has issues recognizing new elements on the page, so the way I fixed this was instead of deleting and adding images to the page, I just edited the existing SRC of images when doing changes, which strangely enough, the jQuery error function responds perfectly to.
Here's the refresh function I ended up coming up with for all interested:
function refreshImages()
{
var images = 10;
for(var i = 0;i < images;i++)
{
var url = getImgUrl();
$('#thumb' + i).attr('src',url);
if(i == 0)
{
$('#fullimage').attr('src',url);
$('.thumb').css('border','2px solid white');
}
}
resize();
}
Related
I have a database with image paths. through PHP, I insert the pictures on my website. The problem is that the code that I have won't work. So, I decided to put some alerts to figure out what is the issue. After going through the alerts, I noticed that the images were resized and repositioned. After some reading, I found out that this is because the javascript is executed in the same time as the HTML and CSS and the alert halts the javascript, letting the HTML and CSS to be executed. How should I change my code to make the images work? This is the code in question:
var box = document.getElementsByClassName("produs");
var pic = document.getElementsByClassName("imagine_produs");
var i;
for (i = 0; i < pic.length; i++) {
alert(pic[i].width);
if ( pic[i].width > 200 ) {
pic[i].width="200";
alert(pic[i].width);
}
var marg = (box[i].clientWidth - pic[i].clientWidth ) / 2;
pic[i].style.marginLeft = marg + "px";
pic[i].style.marginRight = marg + "px";
}
Also, I have made a photo album that is in order to show how the code executes:
What other way is there to either halt the code or to rearrange it so that it works like in the last picture?
THanks!
You might use
console.log()
instead of alert() for debugging purposes. That way you can monitor what your code is doing without interrupting it with prompts.
Apart from that, the funtionality of your code might better be realised with CSS eventually (i.e. margin:auto; img max-width:90%; …).
The code I’m working with is too long to post, so I’ve made a fiddle here: http://jsfiddle.net/Emily92/5b72k225/
This code takes a random image and cuts it up into a number of pieces depending on the class that is applied in the div which contains the image.
When the page loads, a random image is selected from the array and the class is applied to it, what I’m trying to do is create a separate div, which when clicked on will reload the div containing the image. The result I’m looking for is for the image to be replaced by a new random image with the class applied to it.
Right now, the only way I can make a new image appear in the div is to reload the entire page, ideally this would be achieved by just having the div reload instead of all the other page elements reloading too.
I haven’t been able to do this so far but have received some help on here on how to reload an image and class on click of a div, lines 980-1018 of the Javascript code in the jsfiddle is the current attempt at achieving this, but solving this problem seems much more complicated as the image is being manipulated by the Javascript code, so perhaps this needs to also be reloaded at the same time as the new randomised image is selected?
This is the current attempt at solving this problem:
$(function() {
var imageArray = [
'http://www.webdesignhot.com/wp-content/uploads/2009/10/CatsVectorImage.jpg',
'http://www.costume-works.com/images/halloween_cat_in_witch_hat.jpg',
'http://onthewight.com/wp-content/2013/04/sooty-ryde.jpg'];
reloadImages(imageArray);
$('#reload').on('click',function(){
$( "#masterdiv img[id^='div']" ).each(function(index){
$(this).removeClass("jqPuzzle jqp-r"+(index+3)+"-c"+(index+3)+"-SCN");
$(this).fadeOut( "slow", function() {
if(index==0) {
reloadImages(imageArray);
}
$(this).addClass("jqPuzzle jqp-r"+(index+3)+"-c"+(index+3)+"-SCN");
$(this).fadeIn();
});
});
});
});
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
function reloadImages(array){
shuffleArray(array);
for(var i=0;i<3;i++){
// places the first image into all divs
document.getElementById('div'+(i+1)+'id').src=array[0];
}
}
I’ve written more details on the issue in the html section of the jsfiddle. I'd really appreciate any advice in solving this and thank you for any help in advance!
The plugin reads the images' src before page load, takes them and then generates the puzzle. As such, you can not just update the images as they're not there anymore. So you'd have to clear the divs under each difficulty classes (easyDiv,mediumDiv,hardDiv), append a new <img> under each div then calls / reload the plugin. Updated code in : http://jsfiddle.net/5b72k225/6/
Changes I've made:
Separate old reloadImages into initImages and reloadImages. initImages is called in the beginning, while reloadImages is called when reloading.
Created new function makePuzzle by taking out the intialization of the plugin from $(document).ready() block, so makePuzzle can be called after reloading new image.
The new $(document).ready() block now initializes the images and attaches click event handler to the button. When clicked, divs are emptied, new <img>s inserted and plugin is called.
I encounter a problem while performing changes on an img element via javascript:
I build a framework to cycle through different images via the arrow keys of the keyboard. I do this by loading all image urls into an array and then changing the src attribute of the img element accordingly.
So far everything works fine. But now I want to display the naturalHeight and naturalWidth of the current image. Unfortunately when I cycle through the images the sizes of the image preceeding the current image is displayed, although the element shows the correct image.
has this something to do with load order and rendering?
I would be very thankful if someone could help me on that issue.
best regards
Max
On the comments:
I simply load the images by:
imageLeft.setAttribute("src", imagesOld[rowCounter]);
imageRight.setAttribute("src", imagesNew[rowCounter]);
I have a function for updating the size information:
function updateSizeInformation() {
var imageLeftX = $find("<%= txtXImageLeft.ClientID %>");
var imageLeftY = $find("<%= txtYImageLeft.ClientID %>");
var imageRightX = $find("<%= txtXImageRight.ClientID %>");
var imageRightY = $find("<%= txtYImageRight.ClientID %>");
var imageLeft = document.getElementById("imageLeft");
var imageRight = document.getElementById("imageRight");
imageLeftX.set_value(imageLeft.naturalWidth);
imageLeftY.set_value(imageLeft.naturalHeight);
imageRightX.set_value(imageRight.naturalWidth);
imageRightY.set_value(imageRight.naturalHeight);
}
And a function to fit the image to the parent div:
function fitImagesToContainers() {
var divLeft = document.getElementById("imageContainerLeft");
var divRight = document.getElementById("imageContainerRight");
var imageLeft = document.getElementById("imageLeft");
var imageRight = document.getElementById("imageRight");
if (imageLeft.naturalWidth > imageLeft.naturalHeight) {
imageLeft.setAttribute("width", divLeft.clientWidth);
imageLeft.setAttribute("height", divLeft.clientWidth * (imageLeft.naturalHeight / imageLeft.naturalWidth));
} else if (imageLeft.naturalWidth < imageLeft.naturalHeight) {
imageLeft.setAttribute("height", divLeft.clientHeight);
imageLeft.setAttribute("width", divLeft.clientHeight * (imageLeft.naturalWidth / imageLeft.naturalHeight));
}
}
When you set the "src" attribute of an image element the page has not loaded, it normally instigates an asynchronous retrieval of the image file resource. After the image onload event fires the image element properties should represent that of the retrieved image, but be unpredictable before then.
If the code you provided executes synchronously it will run into the problem you report.
In Mozilla Firefox (at least) the image attributes can be that of the previous image if inspected immediately in the same script execution, because the new/next image has yet to be retrieved. Exactly what happens if the page has previously loaded the same image may be unpredictable - I found it giving correct dimension values immediately.
I tested this with standard javascript and do not wish to suggest how to program onload event handlers in jQuery . I did come across this other StackOerflow question on javascript, image onload() doesnt fire in webkit if loading same image which may be of interest.
We have a print functionality in our application where we are printing images in the browser. We are dynamically forming the HTML div with all the image sources [image source is from the webservice url]
When we trigger 'Windows.Print()' , only the first image is always available in print preview (chrome) and remaining images are displayed blank.
If i trigger the print event for the second time, all the images are getting printed without any issue because all the images are cached by that time.
Please let me know how to push all my images in cache before printing. I need to do this in javascript. Dont want to make any html change.
I am using backbone.js and creating a model view with the images. Then Binding the view in HTML. Then i ma using for printing. This works fine in IE and Safari. but not in chrome, it shows print preview screen and always trying to load all the images from browser cache. But i will not be having those images in the browser while giving printing. All my images sources are dynamic and coming from the service. I am just setting the url dynamically to the image source.
<%_.each( Documents, function(oDocument) {%>
<div class="images span1">
<img src="<%- oDocument.URL%>" width="98" height="70" />
</div>
<% });%>
in print preview only one image is coming rest all coming as dots. if i cancel the print and give print again all are coming fine.
Thanks,
Jeevitha
This can be done purely in JavaScript by using the Image object.
var cachedImage = new Image();
cachedImage.addEventListener('load', function () {
alert('Cached image loaded');
});
cachedImage.src = 'http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon.png';
I have created a working JSFIDDLE example showing this at http://jsfiddle.net/pwdst/wc1zrL0v/
The new images could be created in response to a user event, for example clicking on a button, or even scrolling past a certain position. If the image from the server has the proper cache headers, it will then be retained in the browser cache for later use in your print page.
You will be able to see the request in the "Network" tab of the Chrome dev tools, or by using the excellent Fiddler tool from Telerik. Successful load will also trigger the load event listener added in the code sample.
I have called the custom function with the array of images i want to cache. Used Jquery 'Deffered' to hold the next operation until all the images are loaded. This is working very fine
var $deferredimages = $.Deferred();
var items = []; // load all the images paths
PreloadImages(items, loadImageitem, function (){
$deferredimages.resolve();
})
function PreloadImages(items, preloadimages, allDone) {
var count = items.length;
// this callback counts down the things to do.
var pendingimages = function (items, i) {
count--;
if (0 == count) {
allDone(items);
}
};
for (var i = 0; i < items.length; i++) {
// 'do' each thing, and await callback.
preloadimages(items, i, pendingimages);
}
}
function loadImageitem(items, i, onComplete) {
var onLoad = function (e) {
e.target.removeEventListener("load", onLoad);
// this next line can be removed.
// only here to prove the image was loaded.
document.body.appendChild(e.target);
// notify that we're done.
onComplete(items, i);
}
var img = new Image();
img.addEventListener("load", onLoad, false);
img.src = items[i];
img.style.visibility = 'hidden';
}
Reference http://jsfiddle.net/8baGb/1/
I have a report generated by Oracle Apex (A UI tool operating against the Oracle database). I have customized it to have a hyperlink on each record, which when clicked opens a detail report in an iframe right under the current record. This, I am doing by using the Javascript insertRow method on the html table element (Condensed Javascript code below. Oracle APEX allows use of JS/Jquery)
var pTable= html_CascadeUpTill(t,'TABLE');
var myNewRow = pTable.insertRow(pTR.rowIndex+1);
var myNewCell = myNewRow.insertCell(0);
myNewCell.innerHTML = '<iframe src="detail report url" height="0"></iframe>';
In order to resize the height of the iFrame that is different for different detail records, I have the following code in the document).ready(function() of the page
$('iframe').load(function()
{
setTimeout(iResize, 1000);
}
function iResize()
{
// Iterate through all iframes in the page.
for (var i = 0, j = iFrames.length; i < j; i++)
{
var y=(iFrames[i].contentWindow || iFrames[i].contentDocument);
if (y.document)y=y.document;
var docHt = getDocHeight(y);
if (docHt) iFrames[i].height = docHt + "px";
}
}
);
Without the setTimeout call to iResize function, the iframe resize is not happening. But this setTimeout is adding a delay in the resized iframe to appear which I want to avoid. Is there a way to do this? All the related posts/articles I have seen online deal with iframes that are built into the page but not generated on-the-fly as in my case.
Let me know if you need more information. Please help. Thank you.
You should consider putting the details in a <div> block, then showing or hiding the <div> with JQuery. You can set dimensions for your block with CSS, or just let the content flow normally inside of the block. Sounds like a much simpler way to achieve the same effect.
The issue is that if you perform the resize too soon it will get the dimensions of the child document before it has been fully rendered, hence the use of a timer.
If your detail reports are other APEX pages that you control, then you could call the iResize function from the "Execute when page loads" section of the detail page:
parent.iResize();
That seems to work for me.
It sounds to me like the iframes don't even exist when the page first loads.
Instead of calling the iResize function on page load and then every second you could place the call to iResize in the code that creates the iframe.