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!
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).
Related
I've got several items I'm trying to display within a canvas. I've json my php data to support doing this in javascript.
Now I'm trying to iterate the database names with a for loop so I don't have to write the code for each.
Here's what I've got so far:
for ((var i=2; i<=17; i++) && (var j=3; i<=18; j++)){
if((row.g1c[j]y + row.g1c[j]m != 0) && ((12*row.g1c[j]y + row.g1c[j]m) > (360 + (12*row.O1y + row.O1m)))){
var g1c[i]w = (360-(12*row.g1c[i]y + row.g1c[i]m)-(12*row.O1y + row.O1m));
} else if (row.g1c[j]y +row.g1c[j]m != 0){
var g1c[i]w = ((12*row.g1c[j]y + row.g1c[j]m)-(12*row.g1c[i]y + row.g1c[i]m));
} else {}
var g1c[i]x = ((12*row.g1c[i]y + row.g1c[i]m)-(12*row.O1y + row.O1m));
var lineHeight = 15;
var maxWidth = 2.5*(g1c[i]w);
var x = 80+(2.5*(g1c[i]x))+(maxWidth/2);
}
This isn't working and I'm 99.999% sure it has to do with the i and j syntax, but everything I've looked up and tried hasn't worked.
If someone would tell me where my screw-up is, I'd be eternally grateful.
Thanks in advance!
Decided do go down the PHP route vice Javascript to avoid having to redo my database...
I'm creating a for loop for each database column and row...
for ($j=3; $j<=$count; $j++){
$l = "g1c".$j."m";
$m = "g1c".$j."y";
I can then use php logic as needed for each row of data that needs to be assessed...
if(($row[$l] + $row[$m]) != 0){
.... do something
}
You can probably do this:
for (var i=2; i<=17; i++){
for (var j=3; i<=18; j++){
if((row.g1c[j]y + row.g1c[j]m != 0) && ((12*row.g1c[j]y + row.g1c[j]m) > (360 + (12*row.O1y + row.O1m)))){
var g1c[i]w = (360-(12*row.g1c[i]y + row.g1c[i]m)-(12*row.O1y + row.O1m));
} else if (row.g1c[j]y +row.g1c[j]m != 0){
var g1c[i]w = ((12*row.g1c[j]y + row.g1c[j]m)-(12*row.g1c[i]y + row.g1c[i]m));
} else {}
var g1c[i]x = ((12*row.g1c[i]y + row.g1c[i]m)-(12*row.O1y + row.O1m));
var lineHeight = 15;
var maxWidth = 2.5*(g1c[i]w);
var x = 80+(2.5*(g1c[i]x))+(maxWidth/2);
}
}
I have a for loop which looks like this:
for (var i = 0; i < list.length; i++) {
It is looping through Firebase data in the database and returning all the data in the database.
However, I want it to only go up to the first 10 database items. So I changed the loop to:
for (var i = 0; i < 9; i++) {
But this fails to display any results when the there are less than 10 pieces of data in the database. However, if I set the number to however many objects I have in the database, for example 10 because I have 10 objects, it displays them all. But any less than this number and I just get a blank webpage.
Here is the webpage when I have 10 objects in my Firebase database:
And here it is when I remove one of those objects:
I have no idea why this is happening - The logic is correct - if i is less than 9 then display the data - But instead it only displays it when it equals 9.
Here is the full JS:
function refreshUI(list) {
var lis = '';
var lis2 = '';
var lis3 = '';
var lis4 = '';
for (var i = 0; i <= 9; i++) {
lis += '<li data-key="' + list[i].key + '" onclick="addText(event)">' + list[i].book + '</li>';
lis2 += genLinks(list[i].key, list[i].book)
};
for (var i = 10; i < list.length; i++) {
lis3 += '<li data-key="' + list[i].key + '" onclick="addText(event)">' + list[i].book + '</li>';
lis4 += genLinks(list[i].key, list[i].book)
};
document.getElementById('bookList').innerHTML = lis;
document.getElementById('bookList2').innerHTML = lis2;
document.getElementById('bookList3').innerHTML = lis3;
document.getElementById('bookList4').innerHTML = lis4;
};
function genLinks(key, bkName) {
var links = '';
links += '<img src="images/bin.png" style="width: 24px; height: 24px; transform: translateY(-7px); opacity: .4;"></img> ';
return links;
};
function del(key, bkName) {
var response = confirm("Are certain about removing \"" + bkName + "\" from the list?");
if (response == true) {
// build the FB endpoint to the item in movies collection
var deleteBookRef = buildEndPoint(key);
deleteBookRef.remove();
}
}
function buildEndPoint (key) {
return new Firebase('https://project04-167712.firebaseio.com/books/' + key);
}
// this will get fired on inital load as well as when ever there is a change in the data
bookList.on("value", function(snapshot) {
var data = snapshot.val();
var list = [];
for (var key in data) {
if (data.hasOwnProperty(key)) {
book = data[key].book ? data[key].book : '';
if (book.trim().length > 0) {
list.push({
book: book,
key: key
})
}
}
}
// refresh the UI
refreshUI(list);
});
If anybody has any help I'd greatly appreciate it!
When the list size is shorter than 10, you will get an error in the loop because you will eventually address a property (like key) that does not exist on list[i] (since it is undefined). If you would check the console, you would notice that this error is reported.
To fix this, change the condition of the first for loop like this:
for (var i = 0; i < Math.min(10, list.length); i++) {
This way, the loop will never iterate to an entry that does not exist. It will stop after 9 or after list.length-1 whichever comes first.
Alternatively, you can just put the two conditions with an && operator:
for (var i = 0; i < 10 && i < list.length; i++) {
I'm looking for simple solution for a loop where I have to confirm each element. I was looking at pausing and resuming, but it's quite a hassle. Is there any other way to make it easy? I'm sure that this problem is not so rare and many people have stuck upon it.
What I want to achieve is this - I'm looping through the list and if I don't find item by its EAN code then it opens search function to find this and after the item is found (or not) user clicks Next and resume with looping until same situation occurs.
Some code that I have for now:
for(var f = 0; f < biLen; f++){
var ean_parsed = parsedList[i][1];
if(beerList[f].get("ean") === ean_parsed){
console.log("Beer found: " + beerList[f].get("beer_name"));
break;
} else {
if(f === biLen - 1){
//open modal, search for item and then continue looping
console.log("B'r not found: " + parsedList[i][0]);
}
}
}
edit (whole function code instead of piece of it):
function parserCompareList(){
var parsedList = parseResult;
var piLen = parsedList.length;
var beerList = listaPiwArr;
var biLen = beerList.length;
var new_offer = [];
var counter = document.getElementById('imHeader');
for(var i = 0; i < piLen; i++){
counter.innerHTML = i + "/" + piLen; //plain text that's keeping where we actually are with this
for(var f = 0; f < biLen; f++){
var ean_parsed = parsedList[i][1];
if(beerList[f].get("ean") === ean_parsed){
console.log("Beer found: " + beerList[f].get("beer_name"));
break;
} else {
if(f === biLen - 1){
console.log("B'r not found: " + parsedList[i][0]);
}
}
}
}
}
ANSWER:
var indexCache;
function loop() {
var index = indexCache || 0;
for (var f = index; f < biLen; f++) {
var ean_parsed = parsedList[i][1];
if (beerList[f].get("ean") === ean_parsed) {
console.log("Beer found: " + beerList[f].get("beer_name"));
break;
} else {
if (f === biLen - 1) {
// Assuming $modal is the bootstrap modal
indexCache = f;
//$modal.modal().one('hide.bs.modal', loop);
$('#importModal').modal('show').one('hidden.bs.modal', loop) // <-- this one works like a charm
return;
}
}
}
}
loop();
var indexCache;
function loop() {
var index = indexCache || 0;
for (var f = index; f < biLen; f++) {
var ean_parsed = parsedList[i][1];
if (beerList[f].get("ean") === ean_parsed) {
console.log("Beer found: " + beerList[f].get("beer_name"));
break;
} else {
if (f === biLen - 1) {
// Assuming $modal is the bootstrap modal
indexCache = f;
$modal.modal().one('hide.bs.modal', loop);
return;
}
}
}
}
loop();
We have an indexCache variable that holds the index of the beer that is being handled.
If EAN is found, great! we handle it and move on to the next beer.
If not, we store the current beer index in the cache and show the modal and quit the loop immediately. When the modal is hidden, the loop resumes from the cached index.
PS. I am assuming you are using Twitter Bootstrap modal. And therefore, adding a handler to the event 'hide.bs.modal'. But similar thing could be done with your own modal implementation if that is the case.
So im trying to remove HTML div's from it's parent div.
I have a div which contains the div that need to be removed, selectedDivs.
However my current function refuses to remove more then 1 item from it's parent div...
Here's what i tried:
Console output: http://pastebin.com/KCeKv1pG
var selectedDivs = new Array();
canvas.innerHTML += "<div id="+currDev+" class='DRAGGABLE' onClick='addBorder(this)>" + "<img src='/devices/" + device + ".gif'></img></div>";
function addBorder(e) {
if (ctrlBeingpressed == true) {
selectedDivs.push(e);
e.style.border = "2px dotted black";
}
}
function deleteSelected() {
console.log(selectedDivs);
var len = selectedDivs.length;
for (var i = 0, len; i < len; i++){
console.log("before html remove: " + selectedDivs.length);
var node = selectedDivs[i];
node.parentNode.removeChild(node);
console.log("after html remove: " + selectedDivs.length);
for (var i in racks)
{
console.log(i);
if(node.id == racks[i].refdev)
{
console.log("Found in rack");
for (z = 1; z < racks[i].punkt.length; z++)
{
if(racks[i].punkt[z] != undefined)
{
if(racks[i].punkt[z].y.indexOf("S") > -1) //If it's an already defined point at an S card
{
//Clearing the TD
$("#sTab tr:eq("+(cardsS.indexOf(racks[i].punkt[z].y)+1)+") td:eq("+(racks[i].punkt[z].x-1)+")").html(" ");
$("#sTab tr:eq("+(cardsS.indexOf(racks[i].punkt[z].y)+1)+") td:eq("+(racks[i].punkt[z].x-1)+")").css("background-color","#E6E6E6");
}
else // Then it must be a P or V card
{
$("#pvTab tr:eq("+(cardsPV.indexOf(racks[i].punkt[z].y)+1)+") td:eq("+(racks[i].punkt[z].x-1)+")").html(" ");
$("#pvTab tr:eq("+(cardsPV.indexOf(racks[i].punkt[z].y)+1)+") td:eq("+(racks[i].punkt[z].x-1)+")").css("background-color","#E6E6E6");
}
}
}
console.log("Found in rack, breaking this loop");
delete racks[i];
break;
}
}
}
As discussed in the comments, there's a problem with resetting the value of the i variable within the nested loop. I took the liberty of editing the code to the way I would write it. I jQueried up some things since you're already using it anyway. (This code assumes you can target IE 9 or later and thus use Array.prototype.forEach and also that racks is an array, which seemed to be the case from the original.)
var selectedDivs = [];
$(canvas).append("<div id="+currDev+" class='DRAGGABLE' onClick='markSelected(this)'><img src='/devices/" + device + ".gif'></img></div>");
function markSelected(div) {
if (ctrlBeingpressed == true) {
selectedDivs.push(div);
$(div).css("border", "2px dotted black");
}
}
function deleteSelected() {
var i, z, deletedDivIDs = [];
console.log(selectedDivs);
selectedDivs.forEach(function(selectedDiv, index, selectedDivs) {
console.log("Removing", selectedDiv, "at index", index);
divIDs.push(selectedDiv.id);
selectedDiv.parentNode.removeChild(selectedDiv);
});
racks.forEach(function(rack, index, racks) {
console.log(i);
if(deletedDivIDs.indexOf(rack.refdev) !== -1) {
console.log("Found in rack");
for (z = 1; z < rack.punkt.length; z++) {
if(rack.punkt[z] !== undefined) {
if(rack.punkt[z].y.indexOf("S") > -1) {//If it's an already defined point at an S card
//Clearing the TD
$("#sTab tr:eq("+(cardsS.indexOf(rack.punkt[z].y)+1)+") td:eq("+(rack.punkt[z].x-1)+")").css("background-color","#E6E6E6").empty();
}
else { // Then it must be a P or V card
$("#pvTab tr:eq("+(cardsPV.indexOf(rack.punkt[z].y)+1)+") td:eq("+(rack.punkt[z].x-1)+")").css("background-color","#E6E6E6").empty();
}
}
}
racks[rack] = undefined;
}
});
}
I didn't have a chance to test this in real code since we still don't know what racks looks like, but hopefully this gets you further down the road.
you have created nested for loops with the same var i=0, It could be your problem.
And the other point I like to point out is, if racks is an array you'd better not use for(var i in racks) because it would scan all other prototype attributes in your Array.prototype, which depends on what libraries you have used in your page. and If racks is not an array, it would scan all other properties in your Object.prototype, what I mean is, if it is just a iteration using for(var i in racks) is not safe, because adding a new Javascript library could mess with your code.
I have a table with n number of rows with checkboxes and a what i want to do is if i select a checkbox the value should go to the text area, so i stored all elements in an array first, but it isnt happening, as you can see i added alerts as well to check it out. please help.
window.onload = function () {
var oRows = document.getElementById('rnatable').getElementsByTagName('tr');
var iRowCount = oRows.length;
alert('Your table has ' + iRowCount + ' rows.');
var i = 0;
cb = new Array(iRowCount);
while (i <= iRowCount) {
var id = 'check'+ i;
cb[i] = document.getElementById(id);
i++;
}
//alert('Your table has ' + cb[i].value + ' rows.');
for(var a=0; a < iRowCount; a++) {
var fasta = document.getElementById('fasta');
if(cb[a].checked) {
fasta.value = cb.value + ",";
};
};
}
Are you seeing an error in the console? I suspect that when while (i <= iRowCount) runs when i === iRowCount that document.getElementById(id) isn't yielding a result, and that then when you use that value, bad things happen.
Also, each lap through the fasta loop overwrites the previous value. You probably want something like fasta.value += cb.value + ","; instead.