0

Quick question,

I'm a complete JS noob, so I'm having a hard time finding the correct answer on the internet. So I figured I'd ask my question here.

I wrote these two functions.

<script language="javascript" type="text/javascript">

function test() {
show_image("nummer/test.jpg", 120,160, "Firstname Lastname");
show_image("nummer/test2.jpg", 120,160, "Firstname2 Lastname2");
}

function show_image(src, width, height, alt) {
    var img = document.createElement("img");
    img.src = src;
    img.width = width;
    img.height = height;
    img.alt = alt;
    document.body.appendChild(img);
}

//edited piece of code:

function removeImages(){
            var images = document.getElementsByTagName("img");
            for (index = images.length - 1; index >= 0; index--) {
                images[index].parentNode.removeChild(images[index]);
            }
        }

</script>

<button onclick="test();">test</button>

This displays the images perfectly fine, but when you keep clicking the button, it keeps generating images. So if you keep clicking the button, my page fills up with the same images.

I need a way to limit this. I'd like to make the image disappear again when the button is clicked the second time, or when another button is clicked.

Thanks!

EDIT:

Found the solution to my initial problem, the block code is now edited with an extra function to replace the images. I know my code is really not efficient, but it works.

Sander Dult
  • 35
  • 1
  • 6

3 Answers3

1

Edited after OP comment clarification. Think about what your show_image logic is doing. You are creating an image and attaching it each time your button is clicked

Now, what do you want to really do? Answer that, and you have your answer. Let's create a story: Each time I click my button I want to add my two images if they are not on screen, or remove them if they are.

There are a bunch of ways to do this. You could use CSS if you just want to visually hide them, you could destroy and create new images, you can attach/detach the same images, etc. But one thing remains the same: you need to keep track of whether or not the images you're creating have already been created. (This, also, has multiple ways; you could query the dom, you could store references to the items, you could use a boolean switch, etc.).

Here's a live example that uses your original code as a base but keeps track of the image reference we create only once and attaches or removes them from the dom with each button click:

// Define our images in the outer closure.
var img1, img2;

// Handle the button click
function toggleImages() {
  // If we haven't created our images, create and store them in
  // our variables.
  if (!img1) {
    img1 = create_image('http://lorempixel.com/120/160?a', 120, 160, "Firstname Lastname");
  }
  if (!img2) {
    img2 = create_image('http://lorempixel.com/120/160?b', 120, 160, "Firstname Lastname");
  }
  // Toggle our images
  toggle_image(img1);
  toggle_image(img2);
}

function create_image(src, width, height, alt) {
  var img = document.createElement('img');
  img.src = src;
  img.width = width;
  img.height = height;
  img.alt = alt;
  return img;
}

function toggle_image(img) {
  var parent = img.parentElement;
  // If our images are not attached to a parent, attach them.
  // Otherwise, remove them.
  if (!parent) {
    document.body.appendChild(img);
  } else {
    parent.removeChild(img);
  }
}
<button onclick="toggleImages()">Toggle some images!</button><br><br>
rgthree
  • 7,217
  • 17
  • 21
  • Your reasoning is correct, it keeps adding images each time the button is clicked. But I don't need to change the image each time when clicked. I need to display the images on first click. And then I need to hide the images on second click, or when another button is clicked. Hope this clears things up! – Sander Dult Mar 18 '15 at 10:15
  • Oh, yeah, that wasn't very clear to me. I've updated my answer for you then. Hope that helps. – rgthree Mar 18 '15 at 15:28
  • It's a step in the right direction, but when creating a second button with different images, it does not replace the images already present. It simply adds them. When clicking the same button however, it does delete the images corresponding to the button. So that's a step forward. – Sander Dult Mar 25 '15 at 09:01
  • @SanderDult Your comments keep adding more functionality beyond the scope of your original question :) I think my answer more than answers your original question of "I'd like to make the image disappear again when the button is clicked the second time, or when another button is clicked" and gives you a great starting point to continue onward. Godspeed. – rgthree Mar 25 '15 at 14:15
  • This is true, my goal is create a web-based image book, where teachers can demand data on certain classgroups, displaying images of students along with some data corresponding to the student. As I stated a few times, I'm completely new to JavaScript, so I'm trying to find my way. This seemed like a good initial step. Thanks for all the help so far! – Sander Dult Mar 26 '15 at 15:11
0

I had no time to test-run it, but I Hope that solves your problem:

Note I am selecting the img, that has been created and deleting it before appending another one

function test() {
var x = document.querySelector('img');
var body = document.querySelector('body');
if(x){ // if an img has been found do that
   body.removeChild(x);
}
show_image("nummer/test.jpg", 120,160, "Firstname Lastname");
show_image("nummer/test2.jpg", 120,160, "Firstname2 Lastname2");
}

function show_image(src, width, height, alt) {

    var img = document.createElement("img");
    img.src = src;
    img.width = width;
    img.height = height;
    img.alt = alt;
    document.body.appendChild(img);
}
noa-dev
  • 3,561
  • 9
  • 34
  • 72
  • This does not work as such, instead of generating two images each click, it now simply generates one image per click – Sander Dult Mar 18 '15 at 10:17
0

Because you say "when another button is clicked", I assume you are trying to make it so there are multiple buttons, each one loading a different image.

If this is indeed the case, I'd go with the following approach:

// Array of image objects to keep things neat
var images = [
    { "src": "http://placehold.it/120x160", "width": "120", "height": "160", "alt": "Test Image 1" },
    { "src": "http://placehold.it/120x161", "width": "120", "height": "160", "alt": "Test Image 2" }
];
function show_image(image) {
    // Ensure provided index is in array
    if (image < images.length) {
        // Remove this image if already displayed
        if (document.getElementsByClassName("imageNo" + image)[0] !== undefined)
            document.getElementsByClassName("imageNo" + image)[0].outerHTML = "";
        else {
            // Remove other images if displayed
            if (document.getElementById("currentImage") !== null) 
                document.getElementById("currentImage").outerHTML = "";
            var img = document.createElement("img");
            var cur = images[image];
            img.id = "currentImage";
            img.className = "imageNo" + image;
            img.src = cur.src;
            img.width = cur.width;
            img.height = cur.height;
            img.alt = cur.alt;
            document.body.appendChild(img);
        }
    }
    else 
        console.log('No image exists for this index');
}
// Add functionality to buttons
document.getElementById("imageButton1").onclick = function() {show_image(0);}
document.getElementById("imageButton2").onclick = function() {show_image(1);}

Fiddle

If you have one button that you'd like to cycle through all the images, you could use the same approach but change show_image to

var currentImage = 0;
function show_image() {
    // Remove other images if displayed
    if (document.getElementById("currentImage") !== null) 
        document.getElementById("currentImage").outerHTML = "";
    var img = document.createElement("img");
    var cur = images[currentImage++ % images.length];
    img.id = "currentImage";
    img.src = cur.src;
    img.width = cur.width;
    img.height = cur.height;
    img.alt = cur.alt;
    document.body.appendChild(img);
}
function hide_image() {
    // Remove other images if displayed
    if (document.getElementById("currentImage") !== null) 
        document.getElementById("currentImage").outerHTML = "";
    currentImage = 0;
}
// Add functionality to buttons
document.getElementById("imageButton1").onclick = function() {show_image();}
document.getElementById("imageButton2").onclick = function() {hide_image();}

Fiddle

Hope one of these is what you are looking for.

EDIT:

For a multidimensional array you'll need to do the following:

// Array of image objects to keep things neat
var images = [
    //group 1
    [
        { "src": "http://placehold.it/120x160", "width": "120", "height": "160", "alt": "Test Image 1" },
        { "src": "http://placehold.it/120x161", "width": "120", "height": "160", "alt": "Test Image 2" }
    ],
    //group 2
    [
        { "src": "http://placehold.it/120x160", "width": "120", "height": "160", "alt": "Test Image 3" },
        { "src": "http://placehold.it/120x161", "width": "120", "height": "160", "alt": "Test Image 4" }
    ],
];

Obviously if you are going to have 800 images, this is going to be a bit more tedious. Are all the images going to be the same width/height? If they are, I'd take the hit on SEO to go for something like this:

var imageUrls = [
    "http://placehold.it/120x160",  
    "http://placehold.it/120x160", 
    //etc.
];
    // Change this as desired
var itemsPerGroup = 40;
// Returns how many times imageUrls length can be divided into 40 for group count
var images = new Array(Math.floor(imageUrls.length/itemsPerGroup) + 1);
// Initializes child arrays, ensuring last is only as long as it needs to be
for (var i=0; i<images.length; i++)
    images[i] = (i !== images.length - 1) ? new Array(itemsPerGroup) : new Array(images.length % itemsPerGroup);

// Fill arrays
for (var i=0; i<imageUrls.length; i++) {
    // current group
    var group = Math.floor(i/itemsPerGroup);
    // dividend is item number
    var item = i%itemsPerGroup;
    images[group][item] = {
        "src": imageUrls[i],
        "alt": "Group " + group + ", Image " + item,
        "width": "120",
        "height": "160"
    };
}

Using this you'll call images like so

// Array of currentImages
var currentImages = new Array(images.length);
// Initialize
for (var i=0; i<currentImages.length; i++)
    currentImages[i] = 0;

function show_image(group) {
    var imageID = "currentImage" + group;
    var imageContainer = "imageGroup" + group + "Container";
    // Remove other image in group if displayed
    if (document.getElementById(imageID) !== null) 
        document.getElementById(imageID).outerHTML = "";
    var img = document.createElement("img");
    var cur = images[group][currentImages[group]++%images[group].length];
    img.id = "currentImage" + group;
    img.src = cur.src;
    img.width = cur.width;
    img.height = cur.height;
    img.alt = cur.alt;
    document.getElementById(imageContainer).appendChild(img);
}
function hide_image(group) {
    // Remove image in group if displayed
    var imageID = "currentImage" + group;
    if (document.getElementById(imageID) !== null) 
        document.getElementById(imageID).outerHTML = "";
    // Reset currentImage
    currentImages[group] = 0;
}

And of course, a Fiddle showing it in action.

Oceanity
  • 194
  • 1
  • 8
  • I feel like this could work, but I'm missing some things when using them myself. The only thing I changed is "src" (line 3 & 4) to "test.jpg" and "test2.jpg" (which are in the same folder as my html-file). The second part I can't quite grasp are the buttons you are stating. How are you referring to them? I used them in only one direction, referring to my function I want to be executed when clicked. – Sander Dult Mar 18 '15 at 10:23
  • The reason I did this is because in my Fiddle I have the JS separate from the HTML, so the functions ended up being created after the buttons, causing clicking the buttons the way you had them set up to throw a "function is not defined" error. If you use – Oceanity Mar 19 '15 at 16:41
  • So I got this to work, in {show_image(0);} the zero refers to the first line of the array, right? Now how do I refer to multiple lines in this array? I tried {show_image(0,1);}, but this does not seem to work. I've got to display about 800 images, grouped in about 40 images per group (20 groups). So this makes for about 20 buttons each corresponding to about 40 images per button. Thanks! – Sander Dult Mar 25 '15 at 09:46
  • Don't worry about those 800 images though. Once I've got a working example for just two groups of two images, I'll just generate the rest of the 800 lines of code with a regular expression from an excel database – Sander Dult Mar 25 '15 at 10:20
  • It actually won't be too difficult, you'll just need to restructure the image array a bit, I'll update my answer for multidimensional image arrays. – Oceanity Mar 25 '15 at 17:01