Passing image array values and changing image source onclick - javascript

OK, so finally the penny dropped (loud clunk!) on the click issue I was having here Append dynamic div just once and a JSFiddle issue. The code now shows user a choice of pics once per node clicked. Phew.
However, now my img.src=e.target.src line is having trouble accessing the other images in the array. Only the last image in the array will add to the table. I think this is because the allImages.onclick event should be inside the loop?
I have tried that and then img is showing up as undefined. I'm guessing that is because the loop (and therefore the function) is running before var img is declared? I think it is an issue with the order of things.
All help appreciated.
var makeChart = function () {
var table = document.createElement('table'),
taskName = document.getElementById('taskname').value,
header = document.createElement('th'),
numDays = document.getElementById('days').value, //columns
howOften = document.getElementById('times').value, //rows
row,
r,
col,
c;
var myImages = new Array();
myImages[0] = "http://www.olsug.org/wiki/images/9/95/Tux-small.png";
myImages[1] = "http://a2.twimg.com/profile_images/1139237954/just-logo_normal.png";
for (var i = 0; i < myImages.length; i++) {
var allImages = new Image();
allImages.src = myImages[i];
var my_div = document.createElement("div");
my_div.id = "showPics";
document.body.appendChild(my_div);
var newList = document.createElement("ul");
newList.appendChild(allImages);
my_div = document.getElementById("showPics");
my_div.appendChild(newList);
my_div.style.display = 'none';
}
header.innerHTML = taskName;
table.appendChild(header);
header.innerHTML = taskName;
table.appendChild(header);
function addImage(col) {
var img = new Image();
img.src = "http://cdn.sstatic.net/stackoverflow/img/tag-adobe.png";
col.appendChild(img);
img.onclick = function () {
my_div.style.display = 'block';
allImages.onclick = function (e) { // I THINK THIS IS THE PROBLEM
img.src = e.target.src;
my_div.style.display = 'none';
img.onclick=null;
};
}
}
for (r = 0; r < howOften; r++) {
row = table.insertRow(-1);
for (c = 0; c < numDays; c++) {
col = row.insertCell(-1);
addImage(col);
}
}
document.getElementById('holdTable').appendChild(table);
document.getElementById('createChart').onclick=null;
}

Well, the problem seems to stem from different parts. First of all,
for (var i = 0; i < myImages.length; i++) {
var allImages = new Image();
allImages.src = myImages[i];
var my_div = document.createElement("div");
my_div.id = "showPics";
document.body.appendChild(my_div);
var newList = document.createElement("ul");
newList.appendChild(allImages);
my_div = document.getElementById("showPics");
my_div.appendChild(newList);
my_div.style.display = 'none';
}
This loop creates a new div for EACH image in myImages, then appends a ul to that div, and finally appends the Image for the current image to the ul.
The question of what document.getElementById('showPics') returns, since there are as many divs with the id showPics appended to body as myImages.length, has a mystical magical answer which should never be spoken, or even thought, of again.
Why not do the sensible thing and create one singular happy div outside the loop? Append a single ul child to it, outside the loop. Then proceed to append as many li as you want in the loop.
var my_div = document.createElement('div');
my_div.id = 'showPics';
var newList = document.createElement('ul');
my_div.appendChild(newList);
for var i = 0; i < myImages.length; i++) {
...
var li = document.createElement('li');
li.appendChild(allImages);
newList.appendChild(li);
...
}
my_div.style.display = 'none';
Now, my_div is the one and only div containing the images. So, the click event handlers can toggle its visibility safely.
Second,
function addImage(col) {
var img = new Image();
img.src = "http://cdn.sstatic.net/stackoverflow/img/tag-adobe.png";
col.appendChild(img);
img.onclick = function () {
my_div.style.display = 'block';
allImages.onclick = function (e) { // I THINK THIS IS THE PROBLEM
img.src = e.target.src;
my_div.style.display = 'none';
img.onclick=null;
};
}
}
allImages references the same Image object now that you are out of the loop, which happens to be the last image in myImages. So, only the last image in myImages will register the handler to a click event. To solve this problem, we make a new variable.
var sel = null; //This comes before my_div
Now, we add the click handler to allImages inside the loop so that every image in myImages gets a piece of the pie, as they say.
for var i = 0; i < myImages.length; i++) {
var allImages = new Image();
allImages.src = myImages[i];
allImages.onclick = function (e) {
if(sel !== null) {
sel.src = e.target.src;
my_div.style.display = 'none';
sel.onclick=null;
sel = null;
}
};
...
}
And finally, adjust addImage so that sel can be set when the image is clicked.
function addImage(col) {
...
img.onclick = function () {
my_div.style.display = 'block';
sel = img;
}
...
}
That's all there is to it! Example.
Note that, if you comment out sel.onclick = null, you can change a particular cell's image as many times you like.

Your addImage() function makes a direct reference to the allImages variable. One problem is that since you were using (and reusing) that variable in a for loop earlier in the code it is only going to retain the last value that was assigned to it. So no matter how many times you call addImage() it's always adding the onclick function to the last image that allImages pointed to.
I'd also suggest renaming the allImages variable. That's a very misleading name because it in fact only ever represents a single image.
Hope that helps!

Related

ondragstart on an array of elements dynamically in javascript

I have an array of image elements,
var im = ["im1","im2"]; // from db or local drive
Then creating the images dynamically as:
var l = imagelist.length;
for (var i = 0; i < l; ++i) {
if (i in im) {
var s = im[i];
var img = document.createElement("img");
img.src = s;
img.width = width;
img.draggable = true;
var body = document.getElementById("body");
body.appendChild(img);
this.addEventListener('ondragstart', function(event) {
alert(event.target.id);
event.dataTransfer.setData('text/plain', event.target.id);
});
}
While the ondragstart event fires, but alert(event.target.id); shows blank.
That's the reason, the drag and drop functionality is not working for an array of images created dynamically .
Although tried dragging with a single image tag <img> which works absolutely fine, but the array of images doesn't work in this way.
Any solution for this?
You haven't assigned an id to any of your elements.
Something like this should do the trick:
var img = document.createElement("img");
img.src = s;
img.id = "image_" + i;
// The rest of your assignments and code...

Why can't I get my images to appear in table cells/nodes.. maybe I can get some closure?

I want to add a new image in each cell of the new table and give it the same source as the old table, and then make it clickable. Firstly, I did this:
function showData() {
if (localStorage.getItem(name) !== null) {
var showme = localStorage.getItem(name);
alert("I got the table");
var newTable = document.createElement('table');
newTable.innerHTML = showme;
newTable.id = "newTable";
newNumRows = newTable.getElementsByTagName('tr').length;
newNumCells = newTable.getElementsByTagName('td').length;
newNumCols = newNumCells / newNumRows;
alert(newNumRows);
alert(newNumCells);
alert(newNumCols);
var newImages = newTable.getElementsByTagName('img');
for (var i = 0; i < newImages.length; i += 1) {
var picSource = newImages[i]['src'];
console.log(picSource);
}
function addNewImage(newNumCols) {
var newImg = new Image();
newImg.src = picSource;
col.appendChild(newImg);
newImg.onclick = function() {
alert("WOW");
};
}
for (r = 0; r < newNumRows; r++) {
row = newTable.insertRow(-1);
for (c = 0; c < newNumCols; c++) {
col = row.insertCell(-1);
addNewImage(newNumCols);
}
}
var showIt = document.getElementById('holdTable');
showIt.appendChild(newTable);
}
}
This works to a certain extent, but, unfortunately, only the last image was displaying. So, I did a bit of looking around and I think it has to do with closure (apologies for any duplication), but it's a concept I am really struggling to understand. So then I tried this:
function showData() {
if (localStorage.getItem(name) !== null) {
hideTaskForm();
var showme = localStorage.getItem(name);
var oldTable = document.createElement('table');
oldTable.innerHTML = showme;
newTable = document.createElement('table');
newTable.id = "newTable";
var i, r, c, j;
newNumRows = oldTable.getElementsByTagName('tr').length;
newNumCells = oldTable.getElementsByTagName('td').length;
newNumCols = newNumCells / newNumRows;
var newTableCells = newTable.getElementsByTagName('td');
var getImages = oldTable.getElementsByTagName('img');
for (r = 0; r < newNumRows; r++) {
row = newTable.insertRow(-1);
for (c = 0; c < newNumCols; c++) {
makeNodes = row.insertCell(-1);
}
}
for (var j = 0; j < newTableCells.length; j++) {
var theNodeImage = document.createElement("img");
newTableCells[j].appendChild(theNodeImage);
alert(newTableCells[j].innerHTML); //This gives me img tags
}
for (i = 0; i < getImages.length; i += 1) {
var oldSource = getImages[i]['src']; //gets the src of the images from the saved table
console.log(oldSource);
//alert(oldSource);//successfully alerts the image paths
var newPic = new Image(); //creates a new image
(function(newPic, oldSource) {
newPic.src = oldSource;
alert(newPic.src); //gives the same image paths
newTable.getElementsByTagName('img').src = newPic.src; //This doesn't work - table is blank???
})(newPic, oldSource);
}
var showIt = document.getElementById('holdTable');
showIt.appendChild(newTable);
}
}
Now, this doesn't throw any errors. However, nor does it fill the table. It does give me the source and I think I have created the new image objects to attach to the img tags in the newTableCells, but the table is showing up blank. I don't know where I am going wrong. All help really welcome.
Note: Even as a hobbyist, even I know there are probably tons of more efficient ways to do this, but I purposely did it this way to try and help me understand the logic of each step I was taking.
In your code you have:
var newImages = newTable.getElementsByTagName('img');
for (var i = 0; i < newImages.length; i += 1) {
var picSource = newImages[i]['src'];
console.log(picSource);
}
At the end of this, picSource has the value of the last image's src attribute. Then there is:
function addNewImage(newNumCols) {
var newImg = new Image();
newImg.src = picSource;
col.appendChild(newImg);
newImg.onclick = function() {
alert("WOW");
};
}
A value is passed to newNumCols but not used in the function. The value of picSource comes from the outer execution context and is not changed, so it's still the last image src from the previous for loop.
for (r = 0; r < newNumRows; r++) {
row = newTable.insertRow(-1);
for (c = 0; c < newNumCols; c++) {
col = row.insertCell(-1);
addNewImage(newNumCols);
}
}
This loop just keeps calling addNewImage with a single parameter that isn't used in the function, so you get the same image over and over.
For the record, the addNewImage function does have a closure to picSource, but it also has a closure to all the variables of the outer execution contexts. This isn't the issue, though it perhaps masks the fact that you aren't setting a value for picSource on each call, so you get the left over value from the previous section of code.
You haven't provided any indication of the content of showme, so it's impossible to determine if this approach will work at all.
Note
Where you have:
var showme = localStorage.getItem(name);
alert("I got the table");
var newTable = document.createElement('table');
newTable.innerHTML = showme;
newTable.id = "newTable";
IE does not support setting the innerHTML property of table elements, though you can create an entire table as the innerHTML of some other element and set the innerHTML of a cell (tr, th). If you want to use this approach, consider:
var div = document.createElement('div');
div.innerHTML = '<table id="newTable">' + showme + '<\/table>';
var newTable = div.firstChild;

Using a loop, but only one element is being added

I was working on some JavaScript and was trying to add things dynamically. Below is my code. My problem is that I am trying to add three "li" elements, attach "img" tags to it ans attaching the src dynamically. But it is attaching only the last image i.e in my code "bid_3" to all the "li". Help appreciated.
(function() {
var bxSlider = document.createElement("ul"); //created ul
bxSlider.setAttribute("class", "bxslider"); // gave a class name bxslider.
for (i = 1; i < 4; i++) {
var itemsList = document.createElement("li");
var linkImages = document.createElement("img");
linkImages.src = "images/bid_" + i + ".jpg";
itemsList.appendChild(linkImages);
}
bxSlider.appendChild(itemsList);
document.body.appendChild(bxSlider); //append everything to the body.
var ulNum = document.getElementsByTagName("ul");
alert(ulNum.length); // should return 1
var liNum = document.getElementsByTagName("li");
alert(liNum.length); // should return 3
var imgNum = document.getElementsByTagName("img");
alert(imgNum.length); //should return 3
//call the slider.
$(document).ready(function() {
$('.bxslider').bxSlider();
});
}());
PS:- I am not a JavaScript expert. Please forgive if my code is bad.
You're only attaching itemsList after you've passed through the loop. Try this:
// Before loop stuff...
for (i = 1; i < 4; i++) {
var itemsList = document.createElement("li");
var linkImages = document.createElement("img");
linkImages.src = "images/bid_" + i + ".jpg";
itemsList.appendChild(linkImages);
bxSlider.appendChild(itemsList);
}
// After loop stuff...

Can't change Image during onclick event in javascript

I have added image & button dynamically to a webpage. I wrote a "onclick" event, by which the image will be changed on clicking respective button. But the code doesn't work.
My code is;
<style>
.tableclass{
height:80px;}
.imgclass{
height:50px;
width:50px;} </style>
<script>
var img = new Image();
img.src = "Images/circle.png";
img.className = 'imgclass';
window.onload = function init() {
for(var i=0;i<5;i++)
{
var container = document.getElementById('body');
var table = document.createElement('table');
table.className = 'tableclass';
var tr = document.createElement('tr');
var td = document.createElement('td');
var btn = document.createElement('input');
btn.type = 'button';
btn.className = 'buttonclass';
td.appendChild(btn);
td.appendChild(img);
tr.appendChild(td);
table.appendChild(tr);
container.appendChild(table);
}
}
btn.onclick = function(){
document.getElementsByClassName('imgclass').src = "Images/square.jpeg";
};
</script>
<body id="body"></body>
You are adding an event to...
boton.onclick
But I think your variable is named buton - so you need to use:
buton.onclick
Also, as this is running in the loop, you probably want to add the onclick event to each one you create (so put the event binding inside the loop).
Here is a running version of the script:
function getImage() {
var img = new Image();
img.src = "Images/circle.png";
img.className = 'imgclass';
return img;
}
function getRow() {
var img = getImage();
var tr = document.createElement('tr');
var td = document.createElement('td');
var buton = document.createElement('input');
buton.type = 'button';
buton.className = 'buttonclass';
buton.onclick = function(){
img.src = "Images/square.jpeg";
};
td.appendChild(buton);
td.appendChild(img);
tr.appendChild(td);
return tr;
}
var container = document.getElementById('body');
var table = document.createElement('table');
table.className = 'tableclass';
for(var i = 0; i < 5 ; i++) {
table.appendChild(getRow());
}
container.appendChild(table);
You can see it running on JSFiddle.
getElementsByClassName returns a collection, not a single element.
You may do this :
var imgs = document.getElementsByClassName('imgclass');
for (var i=0; i<imgs.length; i++) imgs[i].src = "Images/square.jpeg";
But it would be probably cleaner to give an id to your image and use getElementById.
Note also that you seem to hesitate on the spelling of botón/boton/buton and that will make it hard for the code to work. You should see errors in the console.
There boton has an accent the first time you use it...and why are you using a for loop? I think an array of images could work and every time you click it increments a counter which changes the image. Also use .jpg not .jpeg
This is closer to the original -- I just removed the for loop because I didn't see the need for it...
<style>
.tableclass{
height:80px;}
.imgclass{
height:50px;
width:50px;} </style>
<script>
var count = 0;
var images = [];
images[0] = "Pictures/1.jpg";
images[1] = "Pictures/2.jpg";
images[2] = "Pictures/3.jpg";
images[3] = "Pictures/4.jpg";
var img = new Image();
img.src = images[count];
img.className = "imgclass";
window.onload = function init() {
var container = document.getElementById('body');
var table = document.createElement('table');
table.className = 'tableclass';
var tr = document.createElement('tr');
var td = document.createElement('td');
var button = document.createElement('input');
button.type = 'button';
button.className = 'buttonclass';
button.onclick = function(){buttonClick();}
td.appendChild(button);
td.appendChild(img);
tr.appendChild(td);
table.appendChild(tr);
container.appendChild(table);
}
function buttonClick(){
if(count < images.length - 1){
count++;
}else{
count = 0;
}
img.src = images[count];
};
</script>
<body id="body"></body>

Stop div from adding on every click

I have a table with a background image that, when clicked, displays other images for the user to choose from. This is working and appears or hides on click events. However, when the user clicks to add a second image the menu of images appears again (as it should) but twice. I have commented out a solution I tried. I thought on first click I could display my_div and then delete it in allImages.onclick. This is throwing up a null error in Chrome, probably understandably. The problem here is similar. Hope I added link correctly. Anyway, advice or help appreciated.
function addImage(col) {
var img = new Image();
img.src = "../www/images/TEST.png";
col.appendChild(img);
img.onclick = function () {
var myImages = new Array();
myImages[0] = "../www/images/TEST3.png";
myImages[1] = "../www/images/TEST2.png";
myImages[2] = "../www/images/TEST4.png";
for (var i = 0; i < myImages.length; i++) {
var allImages = new Image();
allImages.src = myImages[i];
var newList = document.createElement("ul");
newList.appendChild(allImages);
my_div = document.getElementById("showPics");
my_div.appendChild(newList);
my_div.style.display = 'block';
allImages.onclick = function (e) {
img.src = e.target.src;
my_div.style.display = 'none';
//var element = document.getElementById("showPics");
//element.parentNode.removeChild(element);
};
}
};
};
for (r = 0; r < howOften; r++) {
row = table.insertRow(-1);
for (c = 0; c < numDays; c++) {
col = row.insertCell(-1);
addImage(col);
}
}
document.getElementById('holdTable').appendChild(table);
I modified your code adding ul to hold all img. It works, but could be better.
function addImage(col) {
var img = new Image();
img.src = "../www/images/TEST.png";
col.appendChild(img);
var myImages = new Array();
myImages[0] = "../www/images/TEST1.png";
myImages[1] = "../www/images/TEST2.png";
myImages[2] = "../www/images/TEST3.png";
var container = document.createElement("ul"); //ul to simplify hide/show
container.style.display = "none";
for (var i = 0; i < myImages.length; i++) {
var newList = document.createElement("li");
var im = document.createElement("img");
im.src = myImages[i];
newList.appendChild(im);
im.onclick = function () {
img.src = this.src;
};
container.appendChild(newList);
}
col.appendChild(container);
col.onclick = function () {
if (container.style.display == "none")
container.style.display = "block";
else
container.style.display = "none";
};
}

Categories

Resources