Return array to parent function call - javascript

I am trying to return an array of objects to a parent function so that I can append them to a div within my HTML.
The function that I have appears to be running an incorrect sequence. Here is my function:
function getRounds() {
var db = connectDB();
var items = new Array();
db.transaction(function(tx) {
tx.executeSql('SELECT * FROM round', [], function(tx, results) {
var len = results.rows.length;
for (var i=0; i<len; i++){
items.push(results.rows.item(i));
}
alert('ONE: '+ JSON.stringify(items));
return items;
}, errorCB);
alert('TWO: '+ items)
});
alert('THREE: '+ items);
return items;
}
What happens is I get an alert of "THREE: ", then "TWO: ", then "ONE: [object]".
Logically it should alert the other way around since the functions are nested, One returns an array of objects which is exactly what I need to be returned to the main function (getRounds).
Any ideas how I can achieve this?
I am using Steroids by Appgyver, the documentation on the Web SQL Database storage can be found here: http://docs.appgyver.com/en/stable/cordova_storage_storage.md.html#SQLResultSetRowList

It's because the call is async! You need to use callbacks!
function getRounds(callback) {
var db = connectDB();
var items = new Array();
db.transaction(function(tx) {
tx.executeSql('SELECT * FROM round', [], function(tx, results) {
var len = results.rows.length;
for (var i=0; i<len; i++){
items.push(results.rows.item(i));
}
alert('ONE: '+ JSON.stringify(items));
callback(items)
}, errorCB);
});
}
getRounds(function(items) {
console.log(items);
});

Related

Store forms in sqlite database

I have researched a lot but have not found solution for my scenario. I have a simple html/javascript app and I package it using cordova. The html page has a form which posts forms to server. I want to save form to sqlite database when the app is offline or no internet connection available.
I am new to sqlite and I have not found any compatible data type to store form to database. If I use TEXT or BLOB it simply stores "[Object HTMLFormObject]" string.
Please check me js code:
db = window.sqlitePlugin.openDatabase({
name: 'ambdb',
location: 'default'
}, function (db) {
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS FORMS (form BLOB)');
}, function (err) {
alert('Open database ERROR: ' + JSON.stringify(err));
});
});
function storeForms(formRecieved) {
//alert(formRecieved.toString());
//alert('text(): '+ formRecieved.text());
//var jsonString = JSON.stringify(formRecieved);
//var htmlText = escape(formRecieved.innerHTML);
//var htmlText = formRecieved.innerHTML;
//var simplyString = String(formRecieved);
db.transaction(function (tx) {
tx.executeSql('INSERT INTO FORMS (form) VALUES (?)', [formRecieved]);
}, function (err) {
alert('StoreForms ERROR: ' + JSON.stringify(err));
});
}
function readForms(cb) {
var submittedForms = [];
db.transaction(function (tx) {
tx.executeSql('SELECT form FROM FORMS', [], function (tx, results) {
alert('total items: ' + results.rows.length);
for (var i = 0; i < results.rows.length; i++) {
var row = results.rows.item(i)['form'];
//row = JSON.parse(row);
/*var varstring = row.toString();
alert('tostring: ' + varstring);
var parser=new DOMParser();
var x = parser.parseFromString(varstring, "text/html");
alert('x: '+ x);*/
submittedForms.push(row);
}
cb.call(this, submittedForms);
});
});
}
document.addEventListener("online", function (e) {
alert('I am online');
isConnected = true;
var promise1 = new Promise(function (resolve, reject) {
readForms(function (forms) {
resolve(forms);
});
}).then(function (submittedForms) {
var numberOfRows = submittedForms.length;
alert('submittedForms.length: ' + numberOfRows);
if (numberOfRows > 0) {
for (var i = 0; i < numberOfRows; i++) {
alert('Single row: '+ JSON.stringify(submittedForms[i]));
submittedForms[i].submit();
}
//deleteForms();
return false;
}
})
}, false);
The commented code shows the possible ways I have tried to serialize-parse HTML object back and forth just to store it in database.
Please guide me what column data type should I use and how should I handle it in code. Many thanks!
I ended up converting HTMLFormObject to JSON object. And I am saving it as a string in database. And while reading from database, I am parsing it back to JSON object. From this JSON object I am creating a html form.
function storeForms(formRecieved) {
var elements = formRecieved.elements;
var newForm = {};
for (var i = 0; i < formRecieved.length; i++) {
var elementName = elements[i].name;
newForm[elementName] = elements[i].value;
}
var jsonString = JSON.stringify(newForm);
db.transaction(function (tx) {
tx.executeSql('INSERT INTO FORMS (form) VALUES (?)', [JSON.stringify(newForm)]);
}, function (err) {
alert('StoreForms ERROR: ' + JSON.stringify(err));
});
}
function readForms(cb) {
var submittedForms = [];
db.transaction(function (tx) {
tx.executeSql('SELECT form FROM FORMS', [], function (tx, results) {
var row, formToSubmit, input, jsonRow = {};
for (var i = 0; i < results.rows.length; i++) {
row = results.rows.item(i)['form'];
jsonRow = JSON.parse(row);
formToSubmit = createFormToSubmit(jsonRow);
submittedForms.push(formToSubmit);
}
cb.call(this, submittedForms);
});
});
}
function createFormToSubmit(jsonData) {
var formToSubmit = document.createElement("form");
var keys = Object.keys(jsonData);
var fieldName, input;
for (var i = 0; i < keys.length; i++) {
fieldName = keys[i];
input = document.createElement("input");
input.type = "text";
input.name = keys[i];
input.value = jsonData[fieldName];
formToSubmit.appendChild(input);
}
formToSubmit.setAttribute('method', "post");
formToSubmit.setAttribute('action', "https:url");
formToSubmit.setAttribute('target', "transFrame");
return formToSubmit;
}

Javascript call by reference not working

I read this and tried implementing my function so that data doesn't change back, but it isn't working with me.
I have an array of objects, where I send them one by one to another function, to add data.
queries.first(finalObject.sectionProjects[i]);
for each one of the sectionProjects, there is a variable achievements, with an empty array.
Upon sending each sectionProject to the queries.first function, I reassign achievements,
finalObject.sectionProjects[i].achievements = something else
When I return from the queries.first function, I lose the data I added.
Am I doing something wrong?
Here's the function:
module.exports = {
first:function(aProject) {
// Latest achievements
var query =
" SELECT ta.description, ta.remarks, ta.expectedECD " +
" FROM project pr, task ta, milestone mi " +
" WHERE pr.ID = mi.project_ID AND mi.ID = ta.milestone_ID " +
" AND ta.achived = ta.percent AND pr.ID = " + aProject.project_id +
" ORDER BY pr.expectedECD " +
" LIMIT 5;"
;
var stringified = null;
pmdb.getConnection(function(err, connection){
connection.query(query, function(err, rows){
if(err) {
throw err;
}else{
var jsonRows = [];
for( var i in rows) {
stringified = JSON.stringify(rows[i]);
jsonRows.push(JSON.parse(stringified));
}
connection.release();
aProject.achievements = jsonRows;
upcomingTasks(aProject);
}
});
});
}
}
This is pmdb.js:
var mysql = require("mysql");
var con = mysql.createPool({
host: "localhost",
user: "user",
password: "password",
database: "database"
});
module.exports = con;
This is the main function that calls queries.first:
// ...Code...
//Number of section projects
var len = jsonRows.length;
console.log("Number of section projects: " + len);
var internal_counter = 0;
function callbackFun(i){
(finalObject.sectionProjects[i]).achievements = [];
queries.first(finalObject.sectionProjects[i]);
if(++internal_counter === len) {
response.json(finalObject);
}
}
var funcs = [];
for (var i = 0; i < len; i++) {
funcs[i] = callbackFun.bind(this, i);
}
for (var j = 0; j < len; j++) {
funcs[j]();
}
Read That Answer twice. Objects acts as a wrapper for the scalar primitive property. You are passing the Objects in to the "queries.first" function.
See this Object reference issue
Edited for the sample code
pmdb.getConnection(function(err, connection){
connection.query(query, function(err, rows){
if(err) {
throw err;
}else{
var jsonRows = [];
for( var i in rows) {
stringified = JSON.stringify(rows[i]);
jsonRows.push(JSON.parse(stringified));
}
connection.release();
aProject.achievements = jsonRows;
upcomingTasks(aProject)
}
});
});
that is not a problem. change it like this. "upcomingTasks" is not a callback function. it is execute after assign the achievements in aProject

Javascript push object into array not working

im using node mirc to retrieve data from mysql
then i want convert data to array, using code below :
function getQuestion (arr{
var obj = {};
connection.connect();
connection.query("SELECT * FROM quiz", function (err, rows, fields) {
if (err) throw err;
for (var i = 0; i < rows.length; i++) {
var row = rows[i];
obj = {"id":row.id, "question":row.question, "answers":row.answers.split(", ")};
f100.push(obj);
};
});
connection.end();
}
f100 = [];
getQuestion();
console.log(f100);
but, its only print []
Due to .query()'s async behavior its taking some time to execute, but you're executing the log just after calling the function. You need to put the log withing callback of .query() function.
function getQuestion (arr{
var obj = {};
connection.connect();
connection.query("SELECT * FROM quiz", function (err, rows, fields) {
if (err) throw err;
for (var i = 0; i < rows.length; i++) {
var row = rows[i];
obj = {"id":row.id, "question":row.question, "answers":row.answers.split(", ")};
f100.push(obj);
};
// do log here
console.log(f100);
});
connection.end();
}
f100 = [];
getQuestion();
connection.query is asynchronous, so i'd recommend consoling out f100 inside the connection.query callback. If you want to do something with f100 after it's finished populating, you'd need to pass it into another function from inside the connection query callback. Example:
connection.query("SELECT * FROM quiz", function (err, rows, fields) {
if (err) throw err;
for (var i = 0; i < rows.length; i++) {
var row = rows[i];
obj = {"id":row.id, "question":row.question, "answers":row.answers.split(", ")};
f100.push(obj);
};
console.log(f100); // should console out correctly here
handleArray(f100); // passes in f100 to a new function
});

Node.js asynchronous coding difficulty

I'm trying to get multiple documents from MongoDB and send all the data in an array, but I'm having serious trouble understanding how this can be done with the event-driven Node.js.
The problem is that at the time dataArray.push(tempObject) is being executed, the tempObject["data"] = tempDataArray still has not been performed.
My code looks like this:
app.post('/api/charts', function(req, res) {
var names = req.body.names;
var categories = req.body.categories;
var dataArray = [];
for (i = 0; i < names.length; i++) {
var tempObject = {};
tempObject["name"] = names[i];
Company.find({ name : names[i] }, function(err, result) {
if (err) {
throw err;
}
var tempDataArray = [];
for (k = 0; k < categories.length; k++) {
var tempDataObject = {};
tempDataObject["name"] = categories[k];
tempDataObject["numbers"] = result[0]["data"][categories[k]]["numbers"];
tempDataObject["dates"] = result[0]["data"][categories[k]]["dates"];
tempDataArray.push(tempDataObject);
}
tempObject["data"] = tempDataArray;
});
dataArray.push(tempObject);
}
res.send(dataArray);
});
Any suggestions on how to properly achieve the desired result would be appreciated.
Use this library
https://github.com/caolan/async
And Using this code, your code will look like this:
var async = require("async");
app.post('/api/charts', function(req, res) {
var names = req.body.names;
var categories = req.body.categories;
var dataArray = [];
async.forEach(names, function(name, callback){
var tempObject = {};
tempObject["name"] = name;
Company.find({ name : name }, function(err, result) {
if (err) {
callback(err);
} else {
var tempDataArray = [];
for (k = 0; k < categories.length; k++) {
var tempDataObject = {};
tempDataObject["name"] = categories[k];
tempDataObject["numbers"] = result[0]["data"][categories[k]]["numbers"];
tempDataObject["dates"] = result[0]["data"][categories[k]]["dates"];
tempDataArray.push(tempDataObject);
}
tempObject["data"] = tempDataArray;
dataArray.push(tempObject);
callback();
}
});
}, function(err){
if(err){
res.send(err);
} else {
res.send(dataArray);
}
});
});
The Company.find() method takes a callback function as it's second parameter. This callback is to be called after the company data is retrieved from the database. This means it could be anywhere between a few milliseconds and a few hundered milliseconds until it is called after calling the Company.find() method. But the code directly after Company.find() will not be delayed; it will be called straight away. So the callback delay is why dataArray.push(tempObject) is always called before tempObject["data"] = tempDataArray.
On top of this the outer for loop will run synchronously and on each iteration a separate DB call will be made. This isn't ideal so we want to get this for loop into the callback. So we can do something like:
app.post('/api/charts', function(req, res) {
var names = req.body.names;
var categories = req.body.categories;
// we just do one DB query where all the data we need is returned
Company.find({ name : names }, function(err, result) {
if (err) {
throw err;
}
var dataArray = [];
// we iteratre through each result in the callback, not outside it since
// that would cause blocking due to synchronous operation
for (i = 0; i < result.length; i++) {
var tempObject = {};
tempObject["name"] = result[i].name;
var tempDataArray = [];
for (k = 0; k < categories.length; k++) {
var tempDataObject = {};
tempDataObject["name"] = categories[k];
tempDataObject["numbers"] = result[i]["data"][categories[k]]["numbers"];
tempDataObject["dates"] = result[i]["data"][categories[k]]["dates"];
tempDataArray.push(tempDataObject);
}
tempObject["data"] = tempDataArray;
dataArray.push(tempObject);
}
res.send(dataArray);
});
});
There are many approaches to abstract Nodes event driven nature such as Promises (which can be accessed either in ECMA Script 6 or a Promise library such as Bluebird, Async, etc.). But the above is a basic callback approach that is typically used in the likes of Express applications.
Simply change this :
tempObject["data"] = tempDataArray;
});
dataArray.push(tempObject);
To:
tempObject["data"] = tempDataArray;
dataArray.push(tempObject);
});

How can I update data in a for loop when my data is returned with a defer after the loop completes

I have two arrays:
$scope.grid.data and $scope.grid.backup
I use the following script to compare the data in each one element at a time:
for (var i = 0, len = $scope.grid.data.length; i < len; i++) {
if (!angular.equals($scope.grid.data[i], $scope.grid.backup[i])) {
var rowData = $scope.grid.data[i]
var idColumn = $scope.entityType.toLowerCase() + 'Id';
var entityId = rowData[idColumn];
entityService.putEntity($scope.entityType, entityId, $scope.grid.data[i])
.then(function (result) {
angular.copy(result, $scope.grid.data[i]);
angular.copy(result, $scope.grid.backup[i]);
}, function (result) {
alert("Error: " + result);
})
}
}
and the following to update the database:
putEntity: function (entityType, entityId, entity) {
var deferred = $q.defer();
EntityResource.putEntity({ entityType: entityType, entityId: entityId }, entity,
function (resp) {
deferred.resolve(resp);
}, function (resp) {
deferred.reject('Error updating');
});
return deferred.promise;
}
This script correctly notices the changes and updates the database.
However there is a problem when the putEntity returns with a result and it then tries to copy the result into $scope.grid.data[i] and
$scope.grid.backup[i]
This happens later and when it tries to do this it always tries to put it into element 11.
Does anyone have any ideas how I can ensure the returned data from putEntity is copied back into the correct element of the grid.data and grid.backup arrays?
You need to create a closure over i. What you can do is create a function
var updateGridData=function(entityType, entityId, gridDataToUpdate, gridIndex)
entityService.putEntity(entityType, entityId,gridDataToUpdate)
.then(function (result) {
angular.copy(result, $scope.grid.data[gridIndex]);
angular.copy(result, $scope.grid.backup[gridIndex]);
}, function (result) {
alert("Error: " + result);
})
}
So your main method becomes
for (var i = 0, len = $scope.grid.data.length; i < len; i++) {
if (!angular.equals($scope.grid.data[i], $scope.grid.backup[i])) {
var rowData = $scope.grid.data[i]
var idColumn = $scope.entityType.toLowerCase() + 'Id';
var entityId = rowData[idColumn];
updateGridData($scope.entityType, entityId, $scope.grid.data[i],i);
}
}
You can get some more idea from this question JavaScript closure inside loops – simple practical example

Categories

Resources