Remote Images !AJAX
"When the only tool you own is a hammer, every problem begins to resemble a nail."
Abraham Maslow
Scripting Remote Images in JavaScript
In the recent weeks I have been asked by several people, who have read my other AJAX articles, to provide examples of using AJAX1 to dynamically load images after page load. These questions are a prime example of Mr. Maslow's quote. Now that remote scripting is virtually ubiquitous every developer wants to use that tool to fix their problems. If you are familiar with JavaScript, the "!" in the title will give you a hint to the solution; it's Not AJAX.
In short, if you already have JavaScript available for use, you do not need the XMLHTTP object to retrieve a remote image. In fact, you can not use AJAX to retrieve a binary stream such as an image file.
So why can't I load a remote image after the page has loaded?
The problem is that once the page is loaded, were you to assign a new source URL to an image or even create a new image object the image will likely not appear in your page. (Depending on the size of the image and the browser.) The Document Object (DOM 2 ) has already been rendered by the browser. If you retrieve an image that was not loaded when the page was loaded, you must insert or append that image's binary stream into the existing page. Let's load a simple page with no image and try to put an image inside a place holder division.
<head>
<script type="text/javascript">
<!--
function getImage(pImageURL) {
var img=new Image();
img.src=pImageURL;
document.getElementById('placeHolder').innerHTML=img.src;
return false;
}
//-->
</script>
<title>Remote Image 1</title>
</head>
<body>
<p><a href="#" onclick="return getImage('/images/rdivilbiss.jpg');">Get Remote Image</a></p>
<div id="placeHolder">Placeholder</div>
</body>
</html>
All that accomplishes is puting the URL of the image into the placeholder. Maybe we need an image tag.
<head>
<script type="text/javascript">
<!--
function getImage(pImageURL) {
var img=new Image();
img.src=pImageURL;
document.getElementById('placeHolder').innerHTML='<img border="0" src="'+pImageURL+'">';
return false;
}
//-->
</script>
<title>Remote Image 2</title>
</head>
<body>
<p><a href="#" onclick="return getImage('/images/rdivilbiss.jpg');">Get Remote Image</a></p>
<div id="placeHolder">Placeholder</div>
</body>
</html>
That puts an image tag in the document but does not display the image data. We just get a blank placeholder. Maybe we need to have a placeholder image and replace the source with the remote image's source.
<head>
<script type="text/javascript">
<!--
function getImage(pImageURL) {
var img=new Image();
img.src=pImageURL;
document.getElementById('placeHolder').src=img.src;
return false;
}
//-->
</script>
<title>Remote Image 3</title>
</head>
<body>
<p><a href="#" onclick="return getImage('/images/rdivilbiss.jpg');">Get Remote Image</a></p>
<img id="placeHolder" border="0" src="/images/placeHolder.jpg">
</body>
</html>
That also does not work. We get an image place holder but when we replace its source either nothing happens or the placeholder image disappears. I think this is when most people begin thinking of AJAX. We know AJAX lets use load data dynamically and we hope we can insert that image data into the wrong place. The answer is really simpler than that and that is, to catch the onload event of the image and APPEND the image to our DOM. We do not need an image tag for a placeholder. We can create it on the fly.
<head>
<script type="text/javascript">
<!--
function getImage(pImageURL){
var img = document.createElement('img');
img.onload = function (evt) {
document.body.appendChild(img);
}
img.src = pImageURL;
return false;
}
//-->
</script>
<title>Remote Image 4</title>
</head>
<body>
<p><a href="#" onclick="return getImage('/images/rdivilbiss.jpg');">Get Remote Image</a></p>
</body>
</html>
That creates a new image element, and attaches a function to its "onload" event such that once the image data has been loaded we can append the image element to our existing (already loaded) document.
If you wanted to change an existing image to one which was not preloaded, you can do it in a similar manner.
<head>
<script type="text/javascript">
<!--
function getImage(pExistingImageID, pImageURL){
var img = document.createElement('img');
img.onload = function (evt) {
document.getElementById(pExistingImageID).src=this.src;
document.getElementById(pExistingImageID).width=this.width;
document.getElementById(pExistingImageID).height=this.height;
}
img.src = pImageURL;
return false;
}
//-->
</script>
<title>Remote Image 5</title>
</head>
<body>
<p><a href="#" onclick="return getImage('placeHolder','/images/rdivilbiss.jpg');">Get Remote Image</a></p>
<p><img id="placeHolder" border="0" src="/images/placeHolder.jpg"></p>
</body>
</html>
NOTE: If the placeholder image is not the same size as the image you retrieve, the original image height and width will not change. I added two lines of code above to correct that problem.
Clearly we are not preloading the images but are retrieving them remotely after the page has completely loaded. Similar to AJAX, the call to retrieve the data requires a function which acts on the data once it has been retrieved. In the case of the XMLHTTP object the function is attached to the XMLHTTP object's "onreadystatechange" event. Here we attach the function to an image object's "onload" event.
Also like the AJAX, once we know the data has been returned we need to insert the data into an existing document. Since it is not text or markup, the innerHTML method is not appropriate and we can either attach the new image to the existing document using the appendChild DOM method or assign its source to an existing image. The reason that did not work in the third attempt was because the assignment occurred before the image data was retrieved. By waiting for the "onload" event we were successful. We just needed the right tool to do the job.
"Production is not the application of tools to materials, but of logic to work."
Peter Drucker
Other Remote Scripting Articles By This Author
AJAHT (AJAX isn't just for XML)
Including Files with JavaScript (No IFRAME, No Hacks)
Geo-Coding IP Addresses Using AJAX
Please Wait! (Letting the user know an AJAX call is pending)
HTTP communications with a Server
Reading A Web Server's Response Headers
1 AJAX = Aynchronous Javascript And Xml
2 DOM = Document Object Model (http://www.w3schools.com/dom/dom_http.asp)
