1

I've read these questions:

and tried to apply their solutions (as well as at least 1/2 a dozen other implementations) and none of them are working.

Here's the function that has the loop:

ExecuteQueryWhereQueryAndParamsBothArrays: function (queryArray, paramsArray, idsArray, success, fail, errorLogging) {
            var hasError = false;
            $rootScope.syncDownloadCount = 0;
            $rootScope.duplicateRecordCount = 0;

            $rootScope.db.transaction(function (tx) {
                for (var i = 0; i < paramsArray.length; i++) {
                    window.logger.logIt("id: " + idsArray[i]);

                    var query = queryArray[i];
                    var params = paramsArray[i];
                    var id = idsArray[i];

                    tx.executeSql(query, params, function (tx, results) {
                        incrementSyncDownloadCount(results.rowsAffected);
                    }, function(tx, error) {
                        if (error.message.indexOf("are not unique") > 0 || error.message.indexOf("is not unique") > 0) {
                            incrementDuplicateRecordCount(1);
                            return false;
                        }

// this didn't work:    errorLogging(tx, error, id);
// so I wrapped in in an IIFE as suggested:
                        (function(a, b, c) {
                            errorLogging(a, b, idsArray[c]);
                        })(tx, error, i);

                        return true;
                    });
                }
            }, function () {
                fail();
            }, function () {
                success();
            });

And here's the errorLogging function that is writing my message (Note, I'm not able to "write" the message in the same javascript file because I'd need to [angular] inject another reference into this file and it would cause a circular reference and the code won't run)

var onError = function (tx, e, syncQueueId) {
    mlog.LogSync("DBService/SQLite Error: " + e.message, "ERROR", syncQueueId);
};

What other method can I implement to stop it from returning the very last "id" of my sync records (when it's only the first record that has the error)?

Community
  • 1
  • 1
ganders
  • 7,285
  • 17
  • 66
  • 114
  • Gee, thanks for closing this. But that exact one you referenced has already been tried and does not work. – ganders Aug 12 '14 at 14:43
  • 3
    Should I be putting links to all of the other implementations that I've tried? – ganders Aug 12 '14 at 14:44
  • No, but you might have made it more clear that you've already tried to apply the solution you found. I needed a second look over the code to see the closure attempt, only highlighted by the commented-out old version. In retrospect, it's actually a quite good question. – Bergi Aug 12 '14 at 15:16

1 Answers1

5
… var i …
async(function() { …
//  errorLogging(tx, error, id);
    (function(a, b, c) {
        errorLogging(a, b, idsArray[c]);
    })(tx, error, i);
… })

That's rather useless, because the i variable already does have the wrong values there. You need to put the wrapper around the whole async callback, closing over all variables are used within the async callback but are going to be modified by the synchronous loop.

The easiest way (works always) is to simply wrap the complete loop body, and close over the iteration variable:

for (var i = 0; i < paramsArray.length; i++) (function(i) { // here
    var query = queryArray[i];
    var params = paramsArray[i];
    var id = idsArray[i];

    window.logger.logIt("id: " + id);
    tx.executeSql(query, params, function (tx, results) {
        incrementSyncDownloadCount(results.rowsAffected);
    }, function(tx, error) {
        if (error.message.indexOf("are not unique") > 0 || error.message.indexOf("is not unique") > 0) {
            incrementDuplicateRecordCount(1);
            return false;
        }
        errorLogging(tx, error, id);
        return true;
    });
}(i)); // and here

You also might pass all variables that are constructed in the loop (and depend on the iteration variable) as the closure arguments. In your case, it might look like this:

for (var i = 0; i < paramsArray.length; i++) {
    (function(query, params, id) { // here
        window.logger.logIt("id: " + id);
        tx.executeSql(query, params, function (tx, results) {
            incrementSyncDownloadCount(results.rowsAffected);
        }, function(tx, error) {
            if (error.message.indexOf("are not unique") > 0 || error.message.indexOf("is not unique") > 0) {
                incrementDuplicateRecordCount(1);
                return false;
            }
            errorLogging(tx, error, id);
            return true;
        });
    }(queryArray[i], paramsArray[i], idsArray[i])); // here
}

Or you identify the async callback, and wrap only that:

for (var i = 0; i < paramsArray.length; i++) {
    window.logger.logIt("id: " + idsArray[i]);
    tx.executeSql(queryArray[i], paramsArray[i], function (tx, results) {
        incrementSyncDownloadCount(results.rowsAffected);
    }, (function(id) { // here
        return function(tx, error) {
//      ^^^^^^ and here
            if (error.message.indexOf("are not unique") > 0 || error.message.indexOf("is not unique") > 0) {
                incrementDuplicateRecordCount(1);
                return false;
            }
            errorLogging(tx, error, id);
            return true;
        };
    }(idsArray[i]))); // and here
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375