-1

I've been trying to figure out why this 'for' only loops once. Having spent about 6 hours re-writing conditions, I was wondering if you could give me a hand with spotting the problem.

Thanks in advance for any piece of advise and your time !

var k;
var i = 1;

function stergeLinie(k) {
    var tabel = document.getElementById('produse');
    var rowCount = tabel.rows.length;

    var row = document.getElementById("tr" + k);
    row.parentNode.removeChild(row);

    var t = rowCount;
    for (y = k; y < t; y++) {
        document.getElementById("nrcrtid" + (y + 1)).value = y;
        document.getElementById("nrcrtid" + (y + 1)).name = "nr_crt" + y;
        document.getElementById("nrcrtid" + (y + 1)).id = "nrcrtid" + y;
        document.getElementById("prodid" + (y + 1)).name = "prod" + y;
        document.getElementById("prodid" + (y + 1)).id = "prodid" + y;
        document.getElementById("umid" + (y + 1)).name = "um" + y;
        document.getElementById("umid" + (y + 1)).id = "umid" + y;
        document.getElementById("cantitateid" + (y + 1)).name = "cantitate" + y;
        document.getElementById("cantitateid" + (y + 1)).id = "cantitateid" + y;
        document.getElementById("pretid" + (y + 1)).name = "pret" + y;
        document.getElementById("pretid" + (y + 1)).id = "pretid" + y;
        document.getElementById("pretfaraTVAid" + (y + 1)).name = "pretfaraTVA" + y;
        document.getElementById("pretfaraTVAid" + (y + 1)).id = "pretfaraTVAid" + y;
        document.getElementById("tvaid" + (y + 1)).name = "tva" + y;
        document.getElementById("tvaid" + (y + 1)).id = "tvaid" + y;
        document.getElementById("tr" + (y + 1)).id = "tr" + y;
        document.getElementById("buton" + (y + 1)).id = "buton" + y;
        document.getElementById("butons" + (y + 1)).onclick = function onclick(event) {
            stergeLinie(y);
        }
        document.getElementById("butons" + y).id = "butons" + (y);
    }
    alert(y);

    document.getElementById("tr" + i).style.height = "100%";
    i--;
}    
  • Depends on what the value of `k` is. Have you done some basic debugging (`console.log()` the values of k and t)? – JJJ May 12 '13 at 16:54
  • Are you sure the execution doesn't fail in the mean time because of some uninitialized variable ? I suggest installing Firebug for Firefox if you haven't done it before. It will show you runtime errors and provides great debugging possibilities. – javadeveloper May 12 '13 at 16:59
  • @Zenith, Juhana, t is defined as a table's number of rows, and k is sent by and HTML onclick event. I've tested many combinations, (k=2,t=8;k5,t=13), all giving the same, unexpected result.@javadeveloper, I've tested it, and the first iteration finishes as it should, and I've checked the variables no end of times. – user2375292 May 12 '13 at 16:59

1 Answers1

1

The main problem is this line:

document.getElementById("butons" + (y + 1)).onclick = function onclick(event) {
        stergeLinie(y);
}

y is getting incremented each time the loop runs (y++), so when the button is actually clicked, y has the value it had on the final iteration - which is just enough to get the loop to run once.

Another issue you're having is this line:

var rowCount = tabel.rows.length;

Where your ids are 1-based, that is the lowest number is 1, whereas the length property is 0 based. If there are 4 rows, rowCount will be 3, meaning that your loop will never reach 4 because the condition is y < rowCount.

Here's a cut down version of your script: http://jsfiddle.net/trolleymusic/XTzjb/ -- I also had to run the function once at the beginning to bind the click in the way that you're doing it.

Here's an updated version that loops correctly: http://jsfiddle.net/trolleymusic/Z8UYp/

var k;
var i = 1;

function stergeLinie(k) {
    console.log("k: " + k);
    var tabel = document.getElementById('produse');
    // Add 1 to the rowCount because the elements have been assigned
    // ids starting with 1, and length is 0-based
    var rowCount = tabel.rows.length + 1;

    var row = document.getElementById("tr" + k);
    row.parentNode.removeChild(row);

    var t = rowCount;

    console.log(t, k);

    for (var y = k; y < t; y++) {
        console.log("Loop: " + y);

        // If the elements don't exist anymore because they were removed
        //   skip the loop
        if (!document.getElementById("butons" + (y + 1))) {
            continue;
        }

        document.getElementById("butons" + (y + 1)).onclick = function onclick(event) {
            // Get the number out of the
            // id of the element that was clicked
            var x = parseInt(this.id.replace("butons",""));
            console.log("x: " + x);
            stergeLinie(x);
        }

    }
}

metadings helpfully added below that you could use a closure for y (http://jsfiddle.net/trolleymusic/dxy6N/)

for (var y = k; y < t; y++) {

    (function (y) {

        document.getElementById("butons" + (y + 1)).onclick = function onclick(event) {
            console.log(y);
            stergeLinie(y);
        }

    }(y));

}

It looks much more complicated, but it's not really. You're putting all of the actions into another function, and passing the value of y to that function as an argument - that means that y is not the same variable as the y that you're incrementing in the loop, it belongs to the function inside the loop. This is closure. The accepted answer to this question: How do JavaScript closures work? gives an excellent explanation of closure.

Community
  • 1
  • 1
Trolleymusic
  • 2,162
  • 3
  • 19
  • 26
  • The function is called by the button, what it does, to be more exact, is it deletes a row in a table, and decrements the names and id's of the following rows. Say y=3, it will turn the (y+1) element, that'd be 4, back to y, into 3, and so on, starting with the 'k' element and ending by turning the 't' element into t-1. – user2375292 May 12 '13 at 17:32
  • Ok, well the failsafe code I've put in there you can probably take out (`if (!document.getElementById("butons" + (y + 1))) { continue; }` -- but the two big issues I found were using `y` in the click function, which is now taken from the number in the element's id, and the rowCount being 0-based, while the elements are 1-based. – Trolleymusic May 12 '13 at 17:42
  • 1
    you're right about the problem, but why don't you explain to him the usual, always working solution, by using a closure for y? `for (var y = 0; y < t; y++) { (function (y) { /**/ })(y); }` – metadings May 12 '13 at 17:53
  • That is a good point. I thought it might be a bit confusing, but I'll add it in. – Trolleymusic May 12 '13 at 17:55
  • @metadings - done. This is a great way of explaining it too: http://stackoverflow.com/questions/111102/how-do-javascript-closures-work – Trolleymusic May 12 '13 at 18:13
  • 1
    it's hard to give points here, because you had to take over some mystery of user's code (like the useless `var k;` outside that will be hidden by the function parameter k, the implicit global `var i`, and you also silently inserted `var` before the y where the k would be sufficient, because it's defined var-like as function parameter)... however you get him/her on the right way ;) – metadings May 12 '13 at 18:31