I want to iterate over a set of p elements and add a dynamically created img element to each one. When the added image is loaded I want to add some text to the p element which contains it using a custom utility function called addText.
My non working code: (See it in action at http://jsbin.com/abebof/2/edit)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Example</title>
<style>img { max-width: 100%; }</style>
</head>
<body>
<p>Image #1</p>
<p>Image #2</p>
<p>Image #3</p>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script>
function addText(paragraph, text) {
paragraph.text(paragraph.text() + '. ' + text);
console.log('called');
}
$('p').each(function (i) {
jthis = $(this);
jthis.css('border', '5px solid');
addText(jthis, 'The function works!');
var jimg = $('<img src="http://i.imgur.com/IH38U.png class="loading" />');
jimg.load(function () {
addText(jthis, 'Loaded!');
});
jimg.appendTo(this);
});
</script>
</body>
</html>
Problems with it I’m asking for help with:
- No image is loaded into the
Image #3paragraph. Why not? - The
Loaded!message is printed into theImage #3paragraph for each image. It should be printed into the paragraph containing the image. How do I rectify it?
A big thanks to mplungjan for helping me out1 Since I feel his answer can be improved further and stick closer to the original code I provide mine too:
Explanations of bug fixes in the OP source:
paragraph.text()retrives the plain text inparagraph, filtering out all other DOM nodes. I tried to change simply the text by usingparagraph.text('the new text')to set simply the text. I was wrong. It effectively sets the plain text and removes everything else which was there. If I think about it that’s logical. After all, if it would simply change the text and keep everything else it wouldn’t be able to know where I wanted the text (ie before or after the img node).imgnode starts loading its image as soon as it can. It does not wait until it’s included in the DOM. Therefore we must first create it without the image URL, then set the load event function and last set the image URL. If we set the URL immediately it’s possible to miss the load event.new function. Confusing? It’s for me too. Read the second answer (not the accepted one, it’s false) here for more information.