My websql transaction won't execute - javascript

I have a mobile app in HTML5 that is using the websql database. I have a data.js file with a bunch of functions for doing various CRUD jobs with the database. I've never had this problem until I got to wiring this function. Basically the app is for creating quotes for tradesmen and the function I'm writing is getting the quote and quote lines, converting them into and array of JSON objects and ajaxing them to a web app.
For some reason my db.transaction's are not being executed. Can you help me figure out why? The db exists as other functions are calling this exact SQL. But it works for them and not this one:
function syncQuote(){
var quote_id = localStorage["quote_id"];
var header = new Array(); // holds id, created, appointment_id
db = openDatabase("Quote", "0.1", "A collection of quotes.", 200000);
if(!db){
console.log('Failed to connect to database.');
}
console.log('Getting quote header data.');
db.transaction(
function(tx) {
tx.executeSql("SELECT * FROM quote_header WHERE id = ?", [quote_id],
function(tx, results) {
var len = results.rows.length;
for(var i=0; i< len; i++){
alert('booyah!');
header['quote_id'] = results.rows.item(i).id;
header['appointment_id'] = results.rows.item(i).appointment_id;
header['created'] = results.rows.item(i).created;
}
});
},
function(tx, error){
console.log(error.message);
}
);
// now get all quote lines for this quote
var lines = new Array();
console.log('getting quote lines');
db.transaction(
function(tx) {
tx.executeSql("SELECT DISTINCT areas.label as area, features.label as feature, products.label as product, hours, price, colour FROM quote_line JOIN areas ON quote_line.area_id = areas.area_id JOIN features ON quote_line.feature_id = features.feature_id JOIN products ON quote_line.product_id = products.product_id WHERE quote_line.quote_id = ?", [quote_id],
function(tx, results) {
len = results.rows.length;
for(var i=0; i< len; i++){
var area= results.rows.item(i).area;
var feature= results.rows.item(i).feature;
var product= results.rows.item(i).product;
var hours= results.rows.item(i).hours;
var price= results.rows.item(i).price;
var colour= results.rows.item(i).colour;
lines[i] = new Array(6);
lines[i][0] = area;
lines[i][1] = feature;
lines[i][2] = product;
lines[i][3] = hours;
lines[i][4] = price;
lines[i][5] = colour;
}
},
function(tx, error){
console.log(error.message);
}
);
}
);
var data = new Array(2);
data[0] = JSON.stringify(header);
data[1] = JSON.stringify(lines);
alert(data[0]);
alert(data[1]);
// post data to web app
var url = "http://*****.com/import_quote";
$.ajax({
type: 'POST',
url: url,
data: data,
success: quote_sync_success,
dataType: 'JSON'
});
}
I have both success and fail callbacks but neither is responding.
Also this is the first time I'm posting JSON from a JS app so feel free to comment.
Thanks,
Billy

Copy this edited codes and see if it works
function syncQuote(){
var quote_id = localStorage["quote_id"];
var header = new Array(); // holds id, created, appointment_id
db = openDatabase("Quote", "0.1", "A collection of quotes.", 200000);
if(!db){
console.log('Failed to connect to database.');
}
console.log('Getting quote header data.');
db.transaction(
function(tx) {
// CORRECTION 1: THE ? IS MEANT TO BE IN A BRACKET
tx.executeSql("SELECT * FROM quote_header WHERE id = (?)", [quote_id],
function(tx, results) {
var len = results.rows.length;
for(var i=0; i< len; i++){
alert('booyah!');
header['quote_id'] = results.rows.item(i).id;
header['appointment_id'] = results.rows.item(i).appointment_id;
header['created'] = results.rows.item(i).created;
}
});
},
function(tx, error){
console.log(error.message);
},
//CORRECTION 2
//THERE IS MEANT TO BE A SUCCESS CALL BACK FUNCTION HERE
function(){
console.log( 'Query Completed' )
}
);
// now get all quote lines for this quote
var lines = new Array();
console.log('getting quote lines');
db.transaction(
function(tx) {
// CORRECTION 3: WRONG CALL METHOD AND NONE-USE OF BRACKETS and QOUTES
tx.executeSql("SELECT DISTINCT areas.label as area, features.label as feature, products.label as product, hours, price, colour FROM quote_line JOIN areas ON quote_line.area_id = 'areas.area_id' JOIN features ON quote_line.feature_id = 'features.feature_id' JOIN products ON quote_line.product_id = 'products.product_id' WHERE quote_line.quote_id = (?)", [quote_id],
function(tx, results) {
len = results.rows.length;
for(var i=0; i< len; i++){
var area= results.rows.item(i).area;
var feature= results.rows.item(i).feature;
var product= results.rows.item(i).product;
var hours= results.rows.item(i).hours;
var price= results.rows.item(i).price;
var colour= results.rows.item(i).colour;
lines[i] = new Array(6);
lines[i][0] = area;
lines[i][1] = feature;
lines[i][2] = product;
lines[i][3] = hours;
lines[i][4] = price;
lines[i][5] = colour;
}
},
function(tx, error){
console.log(error.message);
}
);
}
);
var data = new Array(2);
data[0] = JSON.stringify(header);
data[1] = JSON.stringify(lines);
alert(data[0]);
alert(data[1]);
// post data to web app
var url = "http://*****.com/import_quote";
$.ajax({
type: 'POST',
url: url,
data: data,
success: quote_sync_success,
dataType: 'JSON'
});
}

have you tried throwing console.log()'s in at the start of your success callbacks? if len is 0 in those, you wouldn't get any output from them as is

Related

NodeJs - Error: Can't set headers after they are sent & TypeError: req.next is not a function

I am trying to get some results from the database mysql. I am calling a method to insert into database and another one to read what I inserted before.
I am doing this because node.js not working synchronous. This is my code:
exports.list = function(req, res){
var moduleRows;
req.getConnection(function(err,connection){
var query = connection.query('SELECT * FROM questions WHERE module_id = ?',[X],function(err,rows)
{
for(var i = 0;i < rows.length;i++){
moduleRows = rows[i];
GetResults(moduleRows);
}
});
var GetResults = function(moduleRows) {
var RightAnswer = 0;
var WrongAnswer1 = 0;
var query = connection.query("SELECT * FROM studentsanswers WHERE Question = '"+moduleRows.question+"' ",function(err,rows2)
{
for(var ii = 0;ii < rows2.length;ii++){
if (rows2[ii].Answer == moduleRows.RightAnswer){
RightAnswer++;
}
else if (rows2[ii].Answer == moduleRows.WrongAnswer1){
WrongAnswer1++;
}
}
var Data = {
question: moduleRows.question,
RightAnswer: moduleRows.RightAnswer,
WrongAnswer1: moduleRows.WrongAnswer1,
NumberOfRightAnswer: RightAnswer,
NumberOfWrongAnswer1 : WrongAnswer1
};
insertResults(Data);
return;
});
}
var insertResults = function(Data) {
var query = connection.query("INSERT INTO statistics set ? ",Data, function(err, rows)
{
PrintResults();
return;
});
}
var PrintResults = function() {
var query = connection.query("SELECT * FROM statistics" ,function(err,rows)
{
res.render('StatisticsByModules',{page_title:"Questions - Node.js",data:rows});
return;
});
}
});
};
I am getting the errors:
Error: Can't set headers after they are sent.
TypeError: req.next is not a function
In following code, you call GetResults(moduleRows) few times which calls PrintResults Few times, In your PrintResults Method you are sending res.render few time which you cannot do for a single request. First, you will have to make your data list then call req.render once with queried data.
var query = connection.query('SELECT * FROM questions WHERE module_id = ?', [X], function (err, rows) {
for (var i = 0; i < rows.length; i++) { // <== HERE
moduleRows = rows[i];
GetResults(moduleRows);
}
});

Parse.com Cloud Code, trying to filter query, but query still contains all objects

I'm trying to add unique objects to my parse database, that is, the name property must be different for each object. I try to query for all objects with a given name like so
var query = new Parse.Query(Food);
query.exists("name", name);
query.count({
success: function(number) {....}
However, query.count is always the total number of objects (90) stored on the database, even though there should be 0 or 1 objects with a given name stored.
EDIT:
Following one of the answers, I modified the code to this. However, I still see duplicates in the database.
var query = new Parse.Query(Food);
query.equalTo("name", name);
query.first({
success: function(results) {...}
Below is the entire (edited) function
Parse.Cloud.define("recordFavorite", function(request, response) {
var foodList = request.params.foodList; //string array of food names
var foodListCorrected = new Array();
var Food = Parse.Object.extend("Food");
// Wrap your logic in a function
function process_food(i) {
// Are we done?
if (i == foodList.length) {
//console.log("count is " + foodListCorrected.length);
Parse.Object.saveAll(foodListCorrected, {
success: function(foodListCorrected) {},
error: function(foodListCorrected) {}
});
return;
}
var name = foodList[i];
//console.log("before name is " + name);
var query = new Parse.Query(Food);
query.equalTo("name", name);
query.first({
success: function(results) {
if(!results){
console.log("new");
var food = new Food();
food.set("name", name);
foodListCorrected.push(food);
// console.log(foodListCorrected.length);
} else {
//don't create new food
console.log("exists");
}
process_food(i+1)
},
error: function(error) {
console.log("error");
}
});
}
// Go! Call the function with the first food.
process_food(0);
});
EDIT:
I've tried an alternate approach to this problem using promises, but the line
return Parse.Object.saveAll(foodListCorrected);
does not seem to be executing. I've verified that foodListCorrected is a non-empty array. Below is the entire code for the function.
Parse.Cloud.define("recordFavorite", function(request, response) {
var foodList = request.params.foodList; //string array of food names
var foodListCorrected = new Array();
var Food = Parse.Object.extend("Food");
var query = new Parse.Query(Food);
query.find().then(function(foods) {
for (i = 0; i < foodList.length; i++) {
var j;
for (j = 0; j < foods.length; j++){
if (foodList[i] == foods[j])
break;
}
if (j==foods.length)
foodListCorrected.push(foodList[i]);
}
console.log(foodListCorrected.length);
return Parse.Object.saveAll(foodListCorrected);
}).then(function() {
// Everything is done!
})
});
Try this:
Parse.Cloud.define("recordFavorite", function(request, response) {
var foodList = request.params.foodList; //string array of food names
var saveThese = [];
var FoodClass = Parse.Object.extend("Food");
for(var i = 0; i < foodList.length; ++i){
var food = new FoodClass();
food.set("name", foodList[i]);
saveThese.push(food);
}
Parse.Object.saveAll(saveThese, {
success: function(list){
response.success();
},
error: function(error){
response.error("Failure on saving food");
}
});
});
//If a food already exists in the database, then don't save it
Parse.Cloud.beforeSave("Food", function(request, response){
var query = new Parse.Query("Food");
query.equalTo("name", request.object.get("name"));
query.count({
success: function(count){
if(count > 0)
response.error("Food already exists");
else
response.success();
},
error: function(error){
response.error(error);
}
});
});
The "exists" condition takes in one argument, the name of a key and sees if it exists for a row. So it will return every row where your "name" column has a value, any value. What you're looking for is something like this:
var query = new Parse.Query(Food);
query.equalTo("name", name);
query.first(...)

After I call an array returned from function, it give me "undefined"

I call the facebook fql to get all members of a group. If i check allmembers in the first function, it works just fine, but when i call it in the second one, in returns "undefined".
function getAllMembers(groupid){
var allmembers = new Array();
var content = document.getElementById('content-text');
FB.api({
method: 'fql.query',
query: 'select uid from group_member where gid =' + groupid
},
function(resp){
for (var i=0, l= resp.length; i<l; i++)
{
allmembers[i] = resp[i].uid;
}
return allmembers;
}
)
}
function retrieveMessages(groupid){
var allmembers;
allmembers = getAllMembers(groupid);
console.log(allmembers);
}
I don't understand where's the mistake.
It looks like getAllMembers() is making a asynchronous function call using FB API, which means that the getAllMembers() returns before the FB call is completed.
You need to use a callback function, to solve this problem as given below
function getAllMembers(groupid, callback){
var content = document.getElementById('content-text');
FB.api({
method: 'fql.query',
query: 'select uid from group_member where gid =' + groupid
}, function(resp){
var allmembers = new Array();
for (var i=0, l= resp.length; i<l; i++)
{
allmembers.push( resp[i].uid);
}
callback(allmembers)
})
}
function retrieveMessages(groupid){
getAllMembers(groupid, function(allmembers){
console.log(allmembers);
});
}
At a guess the call is asynchronous - which means that getAllMembers returns before your success function (function(resp){}) executes...
Try moving the console.log inside your function(resp)...
var allmembers = new Array();
function getAllMembers(groupid){
var allmembers = new Array();
var content = document.getElementById('content-text');
FB.api({
method: 'fql.query',
query: 'select uid from group_member where gid =' + groupid
},
function(resp){
for (var i=0, l= resp.length; i<l; i++)
{
allmembers[i] = resp[i].uid;
}
console.log(allmembers);
}
);
}
function retrieveMessages(groupid){
getAllMembers(groupid);
}

Is the unnecessary to loop through the result of an executeSql command?

There's a lot of code here, but the question has to do with the for loop at the bottom.
var dbo = openDatabase('xxx','1.0','myDatabase', 1048576);
var DropTableDeferred = new $.Deferred();
var CreateTableDeferred = new $.Deferred();
var InsertDeferred = new $.Deferred();
var SelectDeferred = new $.Deferred();
dbo.transaction(function(myTrans) {
myTrans.executeSql(
'drop table myTable;'
,[]
,DropTableDeferred.resolve()
);
});
DropTableDeferred.done(function() {
dbo.transaction(function(myTrans) {
myTrans.executeSql(
'CREATE TABLE IF NOT EXISTS myTable'
+ '(xxxID Integer NOT NULL PRIMARY KEY'
+ ',xxxName Varchar(128)'
+ ');'
,[]
,CreateTableDeferred.resolve()
);
});
});
CreateTableDeferred.done(function() {
dbo.transaction(function(myTrans) {
myTrans.executeSql("INSERT INTO myTable(xxxID,xxxName) VALUES(1,'A')");
myTrans.executeSql("INSERT INTO myTable(xxxID,xxxName) VALUES(2,'B')");
myTrans.executeSql(
"INSERT INTO myTable(xxxID,xxxName) VALUES(3,'C')",
[],
InsertDeferred.resolve()
);
});
});
InsertDeferred.done(function() {
dbo.transaction(function(myTrans) {
myTrans.executeSql(
'SELECT * FROM myTable',
[],
function(tx, result) {
SelectDeferred.resolve(result);
}
);
});
});
SelectDeferred.done(function(result) {
var X = $('#result-template').html();
var template = Handlebars.compile(X);
var data = [];
for(var i=0;i < result.rows.length; i++) {
data.push(result.rows.item(i));
}
$('ul').append(template(data));
});
Q: Do I need to build a data array in order to call template(data), or can I pass the result variable directly?
And by 'result variable', what I mean is: result.rows, or result.rows.item, or some other combination.
Yes the value has passed directly in my html&javascript only project. In the code below, I get the results of the Sql and filling a dropdown box's options.
function fillLectureFromDB(tx) {
tx.executeSql('SELECT * FROM LECTURE', [], successFill, errorFill);
}
function successFill(tx, results) {
var len = results.rows.length;
for (var i=0; i<len; i++){
var elOptNew = document.createElement('option');
elOptNew.text = results.rows.item(i).code;
elOptNew.value = results.rows.item(i).code;
var elSel = document.getElementById('slExCode');
elSel.add(elOptNew, null);
}
}
IMHO you can, but to tell you the truth, it would've taken less time for you to try it out then to post the question. Just try:
$('ul').append(template(result.rows));

Web db - getting the data back

Here is the code
onError = function(tx, e) {
alert('Something unexpected happened: ' + e.message );
}
var webdb = openDatabase(dbName, '1.0' , dbDesc , dbSize);
var colourArray = new Array();
webdb.transaction(function(tx) {
tx.executeSql('SELECT * FROM colours',
[],
function(tx,rs) {
var ctn = rs.rows.length;
for (var i=0; i < ctn; i++) {
var row = rs.rows.item(i);
colourArray.push([row.id , row.title]);
}
},
onError);
});
/**
* the array looks like [[1,'red'],[2,'white'],[3,'black'] ...]
*/
var ColourStore = new Ext.data.ArrayStore({fields: ['key', 'val'],
data: colourArray});
The table "colours" contain colour name and hash code. And it was suppose to be use by a ExtJS Ext.data.ArrayStore then populate other drop downs on a massive form.
My problem is - I couldn't get the data back as an array. The variable "colourArray" is empty ... I know I hit some javascript closure , loop problem ... but just couldn't figure out how to get that inner loop value back. Try a lot of return -> return -> return function and more return. None of them works.
executeSQL is asynchronous. You need to create ColourStore in the function(tx,rs) callback function. If you need the data available globally, you can't init your app until executeSQL calls the callback function. Example:
Ext.onReady( function() {
var webdb = openDatabase(dbName, '1.0' , dbDesc , dbSize);
var colourArray = new Array();
var ColourStore;
webdb.transaction( function(tx) {
tx.executeSql('SELECT * FROM colours',
[], function(tx,rs) {
var ctn = rs.rows.length;
for (var i=0; i < ctn; i++) {
var row = rs.rows.item(i);
colourArray.push([row.id , row.title]);
}
//INIT YOUR APP HERE IN ORDER TO HAVE ACCESS TO colourArray values
ColourStore = new Ext....
YourApp.init();
},
onError);
});
}, this);

Categories