websql success callback cannot access variable after query - javascript

related questions(not working):
scope-troubles-in-javascript-...
Pass extra parameters to WebSQL callback function?
I have a 'log' object to capture a few success or error variables as the websql transaction loops through the queries. There is a loop in a loop that is cycling through the data input which is provided from the server in the form of objects in arrays in objects, basically tables then rows. This all works fine until the internal success callback of the sql-query (not the final transaction success.) is called. as you can see from the below i've tried to call a function builder function to capture the table name variable but it is undefined when the returned function is called. I have tried many ways but i either end up with undefined or the last tables entries only.
I have tried to simplify my code below to focus on the issue, some of the code may be messy.I understand why its not available due to asynchronicity but not how to get around it.
addServData = function(data){
var columns, colCount, rowCount, Q, Qmks, table,
rows, dataWatch = {success:{},error:{}};
/*var tableName; //<-- MOVED THIS INTO LOOP AS THOUGHT WAS THE PROBLEM*/
oDb.transaction(function(tx){
for(var key in data){
var tableName = key;
table = data[key];
rows = table.data;
columns = table.columns;
colCount = table.colLen;
rowCount = table.rowLen;
if(rowCount <= 0) continue;
...
Q = 'BUILD QUERY.... (?,?,?)';
for(var x = rows.length-1; x >=0; x--){
var $i = rows.length - (x+1);// <-- INVERT COUNTER
//sort row object to array in order of colums;
var row = rows[$i],
params = utils.sortObjtoArr(row, columns);
tx.executeSql(Q, params,
buildCallback(tblName),
function(tx,error){
console.log('error: ', tx,error);
dataWatch.error[tblName + '::' + params[0]] = error;
});
}
}
function buildCallback(tbl){
//console.log('buildcallback'+tblName, tx); //PRINTS CORRECT NAME;
return function(tx,success,tbl){
console.log('success: ', tx, success, 'tblN:',tbl);//TBL = UNDEFINED;
dataWatch.success[tbl + '::' + success.insertId] = success.rowsAffected;
dataWatch.added += parseInt(success.rowsAffected);
}
}
}, function(tx,error){
console.log(error, dataWatch);
},
function(tx,success){
console.log('success', dataWatch); //WORKS
});
}

A standard oversight on my part, confused myself.
Turns out, in my callback builder, i was trying to retrieve the tbl variable from the sql-queries success caller function not from the scope of the callback builder!
call back should have been:
function buildCallback(tbl){
// return function(tx,success,tbl){ <-- NOT THIS;
return function(tx,success){ // <-- THIS;
console.log('success: ', tx, success, 'tblN:',tbl);//tbl = 'TABLE NAME';
.....
}
}

Related

synchronic node js function

i am quiet new to java script and node js.
i have a problem with a simple function that i call, and it gets done more than one time.
this is my code
app.post('/checkGetSensorIds', function (req, res) {
var tables=['temperature', 'pressure', 'linear_acceleration'];
var ids= [1];
DButils.checkAllSensorsForId(connection, 1 , tables , function(idHasSensorsInfo){
console.log("idHasSensorsInfo is: \n" , idHasSensorsInfo);
});
res.end();
});
/*this function gets a user Id, and the table of all sensors the customer wants, and return true if this
user id has information in all the sesnsor tables that were requested, otherwise returns false*/
exports.checkAllSensorsForId= function(dbConnection, id , sensorsTables, callback){
var sensorsTablesLength= sensorsTables.length;
for (var i = 0; i < sensorsTables.length; i++) {
var tableName= sensorsTables[i];
DButils.checkSingleSensorForId(dbConnection, id, tableName, function(idHasSensorInfo){
if(idHasSensorInfo == false){
callback(false);
return;
}
//in case user have all info in db, we get here and need to return false
if(i == sensorsTablesLength){
callback(true);
return;
}
});
}
};
/*this function gets a user Id, and a single sensor table, and returns true if the user has information
in the requested sensor table, otherwise returns false*/
exports.checkSingleSensorForId= function(dbConnection , id , sensorTable, callback){
var myQuery = 'SELECT count(*) as IdCount FROM ' + sensorTable + ' WHERE id= ' + id;
var query = dbConnection.query(myQuery, function (err, row, result) {
console.log(query.sql);
if (err) {
console.log("checkSingleSensorForId error");
console.error(err);
return;
}
var count= row[0].IdCount;
var idHasSensorInfo = (count > 0);
callback(idHasSensorInfo);
});
};
console.log("idHasSensorsInfo is: \n" , idHasSensorsInfo); is a line that invoked 3 times, while should be only once.
someone has any idea why, and what i need to do to fix it?
You have this line:
DButils.checkAllSensorsForId(connection, 1 , tables , function(idHasSensorsInfo){
console.log("idHasSensorsInfo is: \n" , idHasSensorsInfo);
});
Then you have this:
exports.checkAllSensorsForId= function(dbConnection, id , sensorsTables, callback){
...
for (var i = 0; i < sensorsTables.length; i++) {
...
callback();
...
}
};
So the callback line will be invoked as many times as you call it, which in your case is probably 3 - all it does is call the function from above, so thats why you see it invoked 3 times.
I'm not sure exactly what you are trying to do, but if the callback should be only called once, make sure its ran only once - if it should 'cancel' the for - add a condition to the for or use a promise to resolve whenever you are ready.

Web Sql select statement not able to extract third column

DEMO
I am unable to retrieve third value of the row it is showing undefined when displayed using alert box .What i am basically trying to achieve is insert 4 rows to table and retrieve them as required sorted based on a column
HTML
<div id="status" name="status">Status Message</div>
Javascript
var db = openDatabase('mydb', '1.0', 'Test DB', 4 * 1024 * 1024);
var msg;
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log Text,log1 Text)');
tx.executeSql('INSERT INTO LOGS (id, log,log1) VALUES (1, "foobar","sa")');
tx.executeSql('INSERT INTO LOGS (id, log,log1) VALUES (2, "logmsg","da")');
msg = '<p>Log message created and row inserted.</p>';
document.querySelector('#status').innerHTML = msg;
});
db.transaction(function (tx) {
tx.executeSql('SELECT * FROM LOGS', [], function (tx, results) {
var len = results.rows.length,
i;
msg = "<p>Found rows: " + len + "</p>";
document.querySelector('#status').innerHTML += msg;
for (i = 0; i < len; i++) {
msg = "<p><b>" + results.rows.item(i).log + "</b></p>";
document.querySelector('#status').innerHTML += msg;
var book = results.rows.item(i);
console.log(book);
alert(book.log1);
}
}, null);
});
here i make something very similar to yours, and here it's working. Here my Ids are like:
id integer primary key
So when I do an insert, I don't have to use them, I let web sql take care of it
tx.executeSql('INSERT INTO LOGS (log,log1) VALUES ("logmsg","da")');
Also, I use promises (the code bellow is using angularJs
self.query = function(query, bindings) {
bindings = typeof bindings !== 'undefined' ? bindings : [];
var deferred = $q.defer();
self.db.transaction(function(transaction) {
transaction.executeSql(query, bindings, function(transaction, result) {
deferred.resolve(result);
}, function(transaction, error) {
deferred.reject(error);
});
});
return deferred.promise;
};
self.fetchAll = function(result) {
var output = [];
for (var i = 0; i < result.rows.length; i++) {
output.push(result.rows.item(i));
}
return output;
};
self.fetch = function(result) {
return result.rows.item(0);
};
So I can use it this way:
return DB.query('SELECT * FROM registro WHERE dia = ? and mes = ? and ano = ? order by horario', [dia, mes, ano])
.then(function(result){
return DB.fetchAll(result);
});
I hope this can get you some directions...
Your DEMO link works fine for me (with Chrome 39) - I'm getting 'sa', 'da' alerts after running it. So I think it's something specific to your browser or more probably your cache.
Have you maybe created LOG table without the log1 column at first? Maybe it's still stored in your browser, because
CREATE TABLE IF NOT EXISTS LOGS (id unique, log Text,log1 Text)
line is not going to override it.
In Chrome you can check WebSQL schema hold by the browser with ChromeDevTools and 'Resources' tab, take a look there and see if mydb/LOGS table have your log1 column and data in it.

Cordova SQL - Select data from multiple table

I have a few tables in my SQLite database and each of them have a foreign key that tie each other.
Lets say the structure are like:
Person
=========
Id
Name
Income
=========
IncomeId
PersonId
Income
Contact
=========
ContactId
PersonId
ContactName
The PersonId in both income and contact table are foreign key to the Person table.
Now when i want to query out the data from all the tables, first i select from Person, then in the callback, i will loop through the data, and select from Income and Contact for each of the record. I can't do a join select as the data are not mandatory, i.e. for a Person it might have income but not contact, or vice versa.
However when i try to run through the loop, i found that the result is always the last instance of the data. After some googling the issue seems to be that i need to use Closure.
I tried to implement it but is having a hard time, currently my code looks like this:
for (var i = 0; i < len; i++){
var profile= results.rows.item(i);
var IdAir = profile["IdAir"];
console.log('processing AIR Id: ' + IdAir);
function queryIncomeSuccess(tx,incomeAirResult, currentLoop){
var lenIncomeAir = incomeAirResult.rows.length;
var incomeAIR = {};
if(lenIncomeAir > 0){
incomeAIR = incomeAirResult.rows.item(0);
}else{
incomeAIR = null;
}
if(currentLoop == len - 1)
{
profile["Income"] = incomeAIR ;
airJson[airJson.length] = profile;
}
};
function queryIncome(tx) {
tx.executeSql("SELECT * FROM Income WHERE IdAir = ?",
[IdAir], function(resultSet){
queryIncomeSuccess(tx,resultSet,i);
}, errorCB);
};
db.transaction(queryIncome, errorCB);
}
Is there any guide for multiple select for Cordova? Any help is greatly appreciated. Thanks.
Am able to get this done by using nested function and closure.
The thing to note is that, the closure need to apply at the db.transaction function, rather than on the success callback only.
Code structure used:
//inside for loop of first select result
for (var i = 0; i < len; i++){
function buildSuccessCallback(current,profile){
return function(tx, result){
querySuccess(tx, result,current,profile);
};
}
function querySuccess(tx,result,currentIdx,profile){
//...perform logic
console.log('currentIdx: ' + currentIdx); //returning the correct value
console.log('current Id: ' + profile["IdAir"]); //returning the correct Id
}
db.transaction((function(i,profile){
return function(tx){
tx.executeSql(mySQL, [profile["IdAir"]], buildSuccessCallback(i,profile), errorCB);
};
})(i,profile), errorCB);
}
Thanks.

How To handle result set of websql in html 5?

I m creating mobile web application using html5 and javascript.I m having two javascript files. AttributesDatabase.js and AttributeView.js.From AttributeView.js i m calling one function from AttributeDatabase.js in that i m executing one select query.Now the query result should go to AtttributeView.js.But the Websql transaction is asynchronous call that is what it is not returning proper result.Is there any way to handle the websql result.
Please help if any way there?
Edited
AttributeView.js
var AttributeDAOObj = new AttributeDAO();
AttributeDAOObj.GetAttributeList();
alert(AttributeDAOObj.GetAttributeList()); //This alert is coming as undefined.
AttributeDAO.js
this.GetAttributeList = function () {
var baseDAOObj = new BaseDAO();
var query = "SELECT AttributeName FROM LOGS";
// this.Successcalbackfromsrc = this.myInstance.Successcalback;
var parm = { 'query': query, 'Successcalback': this.myInstance.Successcalback };
baseDAOObj.executeSql(parm);
}
//To Create database and execute sql queries.
function BaseDAO() {
this.myInstance = this;
//Creating database
this.GetMobileWebDB = function () {
if (dbName == null) {
var dbName = 'ABC';
}
var objMobileWebDB = window.openDatabase(dbName, "1.0", dbName, 5 * 1024 * 1024);
return objMobileWebDB;
}
//Executing queries and getting result
this.executeSql = function (query) {
var objMobileWebDB = this.myInstance.GetMobileWebDB();
objMobileWebDB.transaction(function (transaction) {
//In this transaction i m returning the result.The result value is coming.
transaction.executeSql(query, [], function (transaction, result) { return result; }, this.Errorclback);
});
}
}
The problem is in you succes call back (like in the comment to your question, stated by DCoder)
function (transaction, result) { return result; }
this is returning where to?
So this is how to do it (or at least one way)
you can do for example:
function (transaction,result){
console.log("yes, I have some result, but this doesn't say anything, empty result gives also a result");
// so check if there is a result:
if (result != null && result.rows != null) {
if (result.rows.length == 0) {
// do something if there is no result
}else{
for ( var i = 0; i < result.rows.length; i++) {
var row = result.rows.item(i);
var id = result.rows.item(i).id; //supposing there is an id in your result
console.log('Yeah! row id = '+id);
}
}
}else{
// do something if there is no result
}
};
note the code above can be compacter, but this is how to understand it better.
another way is to put this function is a seperate piece of code, so you keep the sql statement more compact and readable. Like you call you error callback this can be in your function (with this. in front of it) or a completely seperate function.

One of my JavaScript variables seem to be getting reset after a jQuery call

My code sends requests to Twitter for search data gets responses in the from of JSON. After getting the JSON, it stores the count of responses that match a certain condition in an array.
Here is the code that makes the call to the function that queries Twitter.
$(document).ready(function() {
...
graph = new HighCharts.chart({
chart: {
events: {
load: function() {
console.log("events.load");
var that = this;
var update = function() {
if (polling) {
console.log("update()");
// The least index series will be nearest the x-axis
var stackNumber = 0;
var numTweets = updateValues();
console.log(numTweets + "");
for (var i = 0, currentSeries = that.series; i < currentSeries.length; i++) {
var x = (new Date()).getTime(), // current time
y = numTweets[i];
stackNumber += y;
currentSeries[i].addPoint([x, y], true, true);
}
}
}
// set up the updating of the chart each second
var series = this.series[0];
setInterval(update, 1000);
}
}
(I'm probably missing some brace somewhere in the code-paste here, but I know for sure that my problem isn't related to a missing brace)
And here is the function that actually queries Twitter using a series of jQuery calls. The updateValues() function (which is outside the document-ready section) goes as follows:
function updateValues() {
var url = "http://search.twitter.com/search.json?callback=?&q=";
var cls = "Penn_CIS240"
var query = "%23" + cls;
var voteCount = [0,0,0,0];
// create an array of zeros
//for (var i = 0; i < 4; i++)
// voteCount.push(0);
$.getJSON(url + query, function(json){
console.log(json);
$.each(json.results, function(i, tweet) {
var user = tweet.from_user_id;
if (user % 2 == 0) {
voteCount[0] += 1;
}
else if (user % 3 == 0) {
voteCount[1] += 1;
}
else if (user % 5 == 0) {
voteCount[2] += 1;
}
else {
voteCount[3] += 1;
}
console.log("updateValues() -> getJSON -> each -> voteCount = " + voteCount);
});
console.log("updateValues() -> getJSON -> voteCount = " + voteCount);
});
console.log("updateValues() -> voteCount = " + voteCount);
return voteCount;
}
What is happening is that the variable voteCount is getting incremented properly inside the jQuery calls. However, outside of the calls, it is getting reset. So the log outputs look something like this:
updateValues() -> getJSON -> each -> voteCount = [1,0,0,0]
updateValues() -> getJSON -> voteCount = [1,0,0,0]
updateValues() -> voteCount = [0,0,0,0]
Does this problem have to do with jQuery's asynchronous calls, and I'm having interesting variable modification conflicts? Or is it something else?
When you use asynchronous callbacks in JavaScript, they execute later... asynchronously. So if you have:
var x = 5;
console.log("before getJSON", 5);
$.getJSON("/some/url", function (json) {
x = 10;
console.log("inside callback", x);
});
console.log("after getJSON", x);
the output will be
before getJSON 5
after getJSON 5
inside callback 10
Any code you want to execute after the request returns must be inside the callback; putting it physically "after" the $.getJSON call will not suffice. You should think of $.getJSON as "firing off" the JSON-getting process, then immediately returning to you; only later, when your script is done executing normal code and the server has responded, will the JavaScript event loop say "hey I got a response and am idle; time to call that callback that was waiting on the response!"
Because of this, your updateValues function will need to accept a callback of its own in order to notify its own caller that the values have been updated; just calling updateValues will only fire off the value-updating process, and the values won't be updated later until that idle time. Something like:
function updateValues(onUpdated) {
var url = "http://search.twitter.com/search.json?callback=?&q=";
var cls = "Penn_CIS240"
var query = "%23" + cls;
var voteCount = [0,0,0,0];
$.getJSON(url + query, function (json) {
// use of json to update voteCount ellided
onUpdated(voteCount);
});
}
Then calling code uses it as
updateValues(function (voteCount) {
// use the updated vote counts inside here.
});

Categories