1

I asked this previously but didn't get an answer that applied to my project. I am trying to load images to a table dynamically without having to use server side code. It works, but I want to be able to have an infinite loop that breaks when a picture fails to load, rather than hard code the number of rows I need. That way I won't ever have to update the code, I'll just be able to add pictures to a folder if I want to expand the table.

Right now the "onerror" attribute hides the failed image, but I also want to break out of the outer loop (loop1).

function headCatalogLoader() {
var table = document.getElementById("catalog");
var meshNum = 0;
var uniqueID = 0;

loop1:
for (var i = 0; i <= 50; i++) {  // i made it 50 instead of infinite for now
    var row = table.insertRow(i);

    loop2:
    for (var k = 0; k <= 2; k++) {      // 2 is because 3 columns
        var skinTone = "none";
        var cell = row.insertCell(k);

        if (k == 0) {
            skinTone = "lgt";
        }
        else if (k == 1) {
            skinTone = "med";
        }
        else if (k == 2) {
            skinTone = "drk";
        }

        cell.innerHTML = "<img src=\"headimgs/head" + skinTone + meshNum + ".png\" id=\"head" + uniqueID + skinTone + "\" onclick=\"previewIt(this)\" onerror=\"$(this).hide();\" />";

        uniqueID++;
    }
    meshNum++;
}
var tbody = $("table tbody");
tbody.html($("tr",tbody).get().reverse());
}

Breaking from within the attribute is out of the loop's scope and doesn't work. Also using

$('img').on("error", function () {
    break loop1;
});

inside loop2 doesn't do anything. Someone suggested I use a recursive method and rewrite my function, but that won't work for me since I'm dynamically creating a table and using image names that correspond to the loop. Any help or suggestions would be wonderful!

chils
  • 63
  • 1
  • 10
  • You can't for loop this. The dom manipulation must wait until the images load before it can decide to stop adding more things to the dom, which happens way after the for loop is finished. You'll need something that works step by step, no idea how but something like https://stackoverflow.com/questions/12354865/image-onload-event-and-browser-cache could maybe trigger adding another batch of images – zapl Sep 14 '18 at 19:40
  • this is an odd loop, not sure the purpose, did you try to set a variable in side on error event handler? and the first loop also use the variable as the loop condition? – Victor Xie Sep 14 '18 at 19:42
  • @Victor Xie the purpose is to fill up a table dynamically with images. The images are named in a way that allows the loop to read the sources. Setting a variable won't do anything because it's the error event handler that is not being recognized. I think zapl is on to something here in that I won't be able to read the errors until the images have fully loaded ie once the loop is complete. – chils Sep 14 '18 at 19:54
  • +1 for the [loop label](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label) I had never seen used before. – webketje Sep 14 '18 at 20:28
  • Also, why should none of the images following the first errored image be loaded? You should have a very special reason for this, as it goes against common practice. – webketje Sep 14 '18 at 20:41
  • @Tyblitz because there ~are no~ images after the first errored image. The error is thrown because the image doesn't exist. At that point I'd want to stop attempting to load any more because that's when they end. It only makes sense when you know that the images are named sequentially, because that's the only way that this would work. Maybe it's not ideal but it's my patchwork solution to avoid server-side code or using lazy load. ps Ikr I was pretty chuffed when I found out labels work in JS – chils Sep 14 '18 at 20:56
  • @chils - that's what I expected, you're going sequentially until you get a `404 not found` error, then want to break out because you've reached the end. My solution below will do the job nicely. Let me know if you have any issues with it, and I'd be happy to help work them out. – Josh Sep 15 '18 at 08:48
  • 1
    @chils - I hope my answer helped you - if it did, I'd really appreciate it if you could accept it? – Josh Sep 17 '18 at 21:48

1 Answers1

1

I'm thinking you could use an XMLHttpRequest to check the response for that URL before trying to put it onto the page. If status is not 404 then insert image else break loop1. Something like this might work:

function headCatalogLoader() {
    var table = document.getElementById("catalog");
    var meshNum = 0;
    var uniqueID = 0;

    loop1:
        for (var i = 0; i <= 50; i++) { // i made it 50 instead of infinite for now
            var row = table.insertRow(i);

            loop2:
                for (var k = 0; k <= 2; k++) { // 2 is because 3 columns
                    var skinTone = "none";
                    var cell = row.insertCell(k);

                    if (k == 0) {
                        skinTone = "lgt";
                    } else if (k == 1) {
                        skinTone = "med";
                    } else if (k == 2) {
                        skinTone = "drk";
                    }

                    // note: you'll need to use an absolute path for imageUrl
                    var imageUrl = "http://example.co.uk/example/headimgs/head" + skinTone + meshNum + ".png";
                    var xhttp = new XMLHttpRequest();
                    xhttp.open('HEAD', imageUrl, false);
                    xhttp.send();

                    if (xhttp.status !== 404) {
                        cell.innerHTML = "<img src=" + imageUrl + " id=\"head" + uniqueID + skinTone + "\" onclick=\"previewIt(this)\" onerror=\"$(this).hide();\" />";
                        uniqueID++;
                    } else {
                        break loop1;
                    }
                }
            meshNum++;
        }
    var tbody = $("table tbody");
    tbody.html($("tr", tbody).get().reverse());
}

Note: you'll need to use an absolute path for the XMLHttpRequest. I've just used example.co.uk/example because I don't know your URL.

I'm guessing you're only expecting it to error if the image is not found, because that would indicate that you've reached the last image in your folder, which is why I checked !== 404, if you want to break in the case of any error (such as 500 internal server error), it might be best to change if (xhttp.status !== 404) to if (xhttp.status === 200).

Josh
  • 376
  • 2
  • 13