Reputation: 165
I'm very new to web design and programming related to it. I'm making a simple gallery using JavaScript, I know it's extremely easy using jQuery. However I'm not allowed to use it (assignment).
Here's the code where the problem is:
var img = new Array(); //declared globally, accessed by other functions
function displayImage(){
var img_num = document.getElementById('img_num').getAttribute("value");
for(j=0;j<img_num;j++)
img.push(document.getElementById('h'+j).getAttribute("value"));
var list_width = 0;
for(var i=0;i<img_num;i++)
{
document.getElementById('list_holder').innerHTML += "<img src='" +img[i]+ "'onclick=\"show(this.id);\" height = \"70%;\"id='"+i+"'/>";
list_width += document.getElementById(i).offsetWidth + 15;
}
document.getElementById('list_holder').style.width = list_width+"px";
return false;
}
Elements with ID's h0,h1,h2... and so on are hidden input types that contain the path of the image and ID's 0,1,2.. are tags.
I'm using them in the JS to store the paths in an array img
using img.push
. Then I'm using the values in the array to create exactly that many <img>
tags (with heights specified, and width left for the aspect ratio to decide. Now it is necessary for me to calculate the total width of the parent div
('list_width') of these img
tags so I thought of using list_width+=document.getElementById(i).offsetWidth
.
But what's happening is, when I open the page for the first time, the actual width is not being returned. It returns 4
, which is basically the min width of an tag I figured. Only on refreshing the page it works as expected. I know I can use a work-around by refreshing the page once just after loading it, but I want to know if there's any 'preferred' or 'professional' way to do it.
Thanks in advance.
Upvotes: 0
Views: 166
Reputation: 23472
As mentioned, you have to wait for the images to finish loading before querying the attributes. Here is an example of what is happening.
img {
width: 50px;
height: auto;
float: left;
border-style:solid;
border-width:1px;
}
img:hover {
width: 300px;
}
<div id="display" class="main"></div>
var display = document.getElementById("display"),
images = {
"F12berlinetta": "http://www.ferrari.com/Site_Collection_Image_115x55/f12_thumb_home_115x55.png",
"458 Spider": "http://www.ferrari.com/Site_Collection_Image_115x55/110823_458_spider_menu.png",
"FF": "http://www.ferrari.com/Site_Collection_Image_115x55/ff_thumb_home_115x55.png",
"458 Italia": "http://www.ferrari.com/Site_Collection_Image_115x55/458_italia_menu_1_dx_ok.png",
"Ferrari California": "http://www.ferrari.com/Site_Collection_Image_115x55/california_menu_3_sx.png"
},
keys = Object.keys(images),
loaded = 0,
menuWidth = 0,
noWaitWidth = 0;
function clickedIt(evt) {
alert("You chose the " + evt.target.title);
}
function onLoaded(evt) {
loaded += 1;
menuWidth += evt.target.offsetWidth;
evt.target.addEventListener("click", clickedIt, false);
if (loaded === keys.length) {
console.log("Waited load width", menuWidth);
}
}
keys.forEach(function (key, index) {
var newDiv = document.createElement("div"),
newImg = document.createElement("img");
newImg.id = "thumb" + index;
newImg.src = images[key];
noWaitWidth += newImg.offsetWidth;
newImg.title = key;
newImg.addEventListener("load", onLoaded, false);
newDiv.appendChild(newImg);
display.appendChild(newDiv);
});
console.log("Didn't wait load width", noWaitWidth);
on jsfiddle
Addition: This places HTML image markup in the document in a standard javascript manner, if that is what you mean. Without you describing what you do not understand, it is difficult to simplify any explanation; There is an object that holds the image title and its URL. We loop through the object and place the image in the document along with the title and get the incorrect image width, on each image we set an event listener that waits for the image to load, when it loads we get the correct image width. We also set click listener on each image which gives an alert of which image you clicked. The CSS demonstrates its standard hover method, so that when you place the move over an image it zooms that image.
Upvotes: 2
Reputation: 22617
You have to wait until the images are loaded. You are new to Javascript but you already have to face asynchronous programming. Let's see this in the comments:
var img = []; // faster to type, use this syntax if you
// don't define an initial length
function displayImage() {
// The attribute value defines the initial value of the input element, and
// it may differ from the actual value. So use the value property, not the
// attribute.
var img_num = document.getElementById('img_num').value;
for(var j=0; j<img_num; j++) // Watch out, without var j is global!
img.push(document.getElementById('h'+j).value);
var list_width = 0,
// We're referincing this element a lot, better store it
lholder = document.getElementById('list_holder'),
htmllist = []; // See the trick
for(var i=0; i<img_num; i++)
htmllist.push("<img src='" +img[i]
+ "'onclick=\"show(this.id);\" height = \"70%;\"id='"+i+"'/>");
// Every time you set innerHTML, using = or +=, the browser has to parse
// the code and rebuild the content, and it's an expensive task. Set this
// property only once you already computed all the HTML you need.
lholder.innerHTML = htmllist.join("");
var loaded = 0;
for(var i=0; i<img_num; i++)
// You don't know when the images will be loaded. But when an image is
// loaded, it triggers the load event that you can listen setting the
// onload property (or, in a more modern way, setting an event listener
// with addEventListener or attachEvent in older IE). Count the images
// that are loaded, and when they're all loaded do your stuff.
lholder.childNodes[i].onload = function() {
if (++loaded < img_num) return;
for(var i=0; i<img_num; i++)
list_width += lholder.childNodes[i].offsetWidth;
lholder.style.width = list_width + "px";
};
return false;
}
Upvotes: 2
Reputation: 17930
This line has a problem:
for(var i=0;i<img_num;i++)
document.getElementById('list_holder').innerHTML += "<img src='" +img[i]+ "'onclick=\"show(this.id);\" height = \"70%;\"id='"+i+"'/>";
list_width += document.getElementById(i).offsetWidth + 15;
since you don't have curley braces it will only run the first line in the loop, change it to this:
for(var i=0;i<img_num;i++){
document.getElementById('list_holder').innerHTML += "<img src='" +img[i]+ "'onclick=\"show(this.id);\" height = \"70%;\"id='"+i+"'/>";
list_width += document.getElementById(i).offsetWidth + 15;
}
Upvotes: 0