Garrett
Garrett

Reputation: 1688

Nested HTML5 Web SQL Query Issued after Entire For Loop Processed

In this query listed below, my for loop is executing 4 values. In the first alert(id), it is alerting those 4 distinct values. However, in the nested query, the alert statement is printing out the last id value only, 4x with different max(b.id) values. I'm confused. Does anyone know what may be happening? Could a race condition be occurring?

My goal is to place an Ajax call in the nested query, which has input values based on both id and b.id. I am currently doing this, but the value in the ajax call for the "id" is the same for all 4 different calls, which messes up the return data. Thanks.

database.db.transaction(function (tx) {
            tx.executeSql('SELECT id, name from programs d', [], function (tx, results) {
                for (var i = 0; i < results.rows.length; i++) {
                    var id = results.rows.item(i)['id'];
                    var name = results.rows.item(i)['name'];
                        alert(id);

                    tx.executeSql('SELECT max(b.id) + 1 max from people b where b.sid = ?',
                        [id],
                        function (tx, results) {
                            lastRecord = results.rows.item(0)['max'];
                            alert(id + "last rec: " + name);
                        }
                    );
                }
            },
            function (event) { alert(event.message); });

Upvotes: 0

Views: 2401

Answers (1)

Mike Ryan
Mike Ryan

Reputation: 4374

As per my comments, you to return a closed function to bind the parameter correctly.

A much simpler example is the following:

Running this produces 4 alerts, all showing 4:

for (i=0;i<4;i++) {
    setTimeout( function() { alert(i)}, 1000);
}

Running this produces 4 alerts, showing 0/4, 1/4, 2/4, 3/4.

for (i=0;i<4;i++) {
    setTimeout(function(inneri) { 
        return( 
            function() { 
                alert(inneri + "/" + i);
            }
        );
    }(i), 1000);
}

where I've named inneri the value that was preserved upon closure. Note that i, itself is still referring to the outer scope, and thus is 4 (which is what is true at time of execution, since that is the value of i when it dumps out of the for loop, as we're delaying the execution using setTimeout().

The first case is a simpler version of what you're doing, whereas you want the second case.

Rewriting your js (and hoping I get all these ( and {'s in the right place :) ) gives:

database.db.transaction(function (tx) {
      tx.executeSql('SELECT id, name from programs d', [], function (tx, results) {
            for (var i = 0; i < results.rows.length; i++) {
                var id = results.rows.item(i)['id'];
                var name = results.rows.item(i)['name'];
                alert(id);

                tx.executeSql('SELECT max(b.id) + 1 max from people b where b.sid = ?',
                    [id],
                    function(innerId) { 
                       return (
                          function (tx, results) {
                                lastRecord = results.rows.item(0)['max'];
                                alert(innerId + "last rec: " + name);
                          }
                       );
                    }(id) //be careful to avoid the ";" here!
                );
            }
        },
        function (event) { alert(event.message); 
    });

Where I have inserted:

 function(innerId) { 
    return (
         function (tx, results) {
             lastRecord = results.rows.item(0)['max'];
             alert(innerId + "last rec: " + name);
         }
    );
 }(id)

in. This function is called immediately via the (id) and returns a function that takes tx and results as arguments and does the appropriate action.

I have checked braces/parenthesis, but don't have a direct way to verify that I didn't make any typos.

Upvotes: 2

Related Questions