I just got bitten by something really nasty, so thought I’d care to share…
Symptom
On a certain page, we are outputting 10 divs each of which contained a radio button and an image. In Safari, (and it turned out IE), each time I refreshed, only some of those 10 divs were rendered. Sometimes it would be 5, sometimes 8, sometimes none displayed at all - it all seemed to be completely random. However… the weird thing was that all 10 divs showed correctly in the source!
Problem 1: No indication that javascript was in use
For quite a while, I thought this was some very weird, and obscure browser issue with Safari. It turned out that the culprit for this very weird behaviour was a jQuery function being applied to the those divs which shared a common class.
Our normal best practice is to use classes starting with js_ for anything that we’re going to apply jQuery calls to. In this case, that wasn’t done, which led me down the proverbial garden path.
Problem 2: jQuery initialisation
Having figured out that javascript was in play, I found this jQuery function being applied:
var Bookmarks = {
init: function(){
$('div.candidate_image img').each(function(){
if (($(this).width() < 50) || ($(this).height() < 50)) {
$(this).parent().hide();
}
});
}
};
It hides those divs where the contained image is less than 50px in either dimension, and was being called where we initialised all our other jQuery stuff in a block like this:
// initialisers go here
$(document).ready(function(){
...
Bookmark.init();
...
}
The problem is, the images were remote images stored on other servers, and took a while to load. Therefore when the Bookmarks.init function was called, some of the images wouldn’t yet have been loaded fully from the remote sites, and therefore had width: 0, height: 0. This is why the divs would randomly be displayed or not, because it depended on whether the images had managed to load fully.
Solution
The way round this, is to put the Bookmark.init() inside a load() handler, instead of the ready() one, like this:
$(document).load(function(){
...
Bookmark.init();
...
}
This gets run once everything has been loaded (including images), rather than just when the DOM structure is ready.