Javascript: How to get a value from a function inside a method - javascript

I trying to get the value (true or false) from nested functions inside of a method, but value returns UNDEFINED. How I can get a value from a object nested function?
var result = {
compute: function() {
this.retorno = result.transaction();
},
transaction: function() {
var db = window.sqlitePlugin.openDatabase({name: 'database.db', location: 'default'});
db.transaction(checaFR,erroFR); //Check if (F)irst (R)un.
function checaFR(tx){ //Check if table exists
tx.executeSql('SELECT * FROM setup',[],checaFRSuccess,erroFR2);
alert("Select Query OK");
}
function erroFR(err){ //Return if error
alert('Ops - '+err);
return false; //This value I Need! :(
}
function checaFRSuccess(tx,result){
alert("Query Sucess "+result.rows.length);
return ('Rows: '+result.rows.length);
}
function erroFR2(err2) { //If no DB table
alert("erroFR2: "+JSON.stringify(err2));
db.transaction(populateDB, errorCB, successCB); //Start DB Populate
}
function populateDB(tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS setup (id INTEGER PRIMARY KEY AUTOINCREMENT, runned TEXT NOT NULL)');
tx.executeSql('INSERT INTO setup(runned) VALUES ("1")');
}
function errorCB(errCB) {
alert("Error processing SQL: "+errCB);
return false; //This value I Need! :(
}
function successCB() {
alert("successCB OK");
return true; //This value I Need! :(
}
}
};
result.compute(); //Start the main function
return {
retorno: "var: "+result.retorno //This returns UNDEFINED
};
How I can get the value from this function and pass it?
Note: All callbacks and alerts are working, including the database creation. :D

You can refer to the function nested inside using the following code.
result.transaction().erroFR();
result.transaction().errorCB();
But before that you need to return the Object from the inner function which needs to be publicly accessible. This is basically a module pattern, where you can expose only the relevant information to outside world. So you need to expose the functions as shown below. Note the return statement at the end of the function which is returning an object.
var result = {
compute: function() {
this.retorno = result.transaction();
},
transaction: function() {
var db = window.sqlitePlugin.openDatabase({name: 'database.db', location: 'default'});
db.transaction(checaFR,erroFR); //Check if (F)irst (R)un.
function checaFR(tx){ //Check if table exists
tx.executeSql('SELECT * FROM setup',[],checaFRSuccess,erroFR2);
alert("Select Query OK");
}
function erroFR(err){ //Return if error
alert('Ops - '+err);
return false; //This value I Need! :(
}
function checaFRSuccess(tx,result){
alert("Query Sucess "+result.rows.length);
return ('Rows: '+result.rows.length);
}
function erroFR2(err2) { //If no DB table
alert("erroFR2: "+JSON.stringify(err2));
db.transaction(populateDB, errorCB, successCB); //Start DB Populate
}
function populateDB(tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS setup (id INTEGER PRIMARY KEY AUTOINCREMENT, runned TEXT NOT NULL)');
tx.executeSql('INSERT INTO setup(runned) VALUES ("1")');
}
function errorCB(errCB) {
alert("Error processing SQL: "+errCB);
return false; //This value I Need! :(
}
function successCB() {
alert("successCB OK");
return true; //This value I Need! :(
}
// Return an object containing functions which needs to be exposed publicly
return {
checaFR : checaFR,
erroFR : erroFR,
checaFRSuccess : checaFRSuccess,
erroFR2 : erroFR2,
populateDB : populateDB,
errorCB : errorCB,
successCB : successCB
}
}
};

You need to pass a callback function into the result.transaction method, and the false value would be passed into that callback function.
You have to do this bc false is derived during/after db.transaction, which is an asynchronous method... so we have to pass false asynchronously as well.

Related

Why is my promise's 'resolve' being sent before the functions ends execution?

I have a function (that contains promises internally so it itself runs synchronously) that seems to be running asynchronously within my main code. No matter how I format my promise it seems like the resolve gets sent before the functions ends execution:
This problem is also logically recursive, in that if I try adding another promise around the nameExists function (within this very promise) and then putting the resolve in a 'then', i just run into the same issue with the nested resolve...
document.getElementById("config-select").addEventListener("input", function(){
//check if the doc name exists: returns doc id
//promise that doc_obj is created before moving on
let doc_obj = {};
let promise = new Promise(function (resolve, reject) {
let doc_name = document.getElementById("config-select").value;
doc_obj = nameExists(doc_name);
resolve('done'); //this executes BEFORE nameExists is done processing...bringing back the original asynch issue i was trying to fix in the first place...
});
promise.then(function (result) {
alert("then: "+doc_obj);
if(doc_obj.bool === true){//it does exist:
alert("replacing id");
document.getElementById("config-select").setAttribute("doc-id", doc_obj.id);
}
else{//it doesn't:
alert("resetting id");
document.getElementById("config-select").setAttribute("doc-id", "");
}
}
);
});
The nameExists function:
//check if the name in config-select is an existing doc (assumes name is a unique document field)
const nameExists = function(name){
//get all docs
localDB.allDocs({include_docs: true}).then(function (result) {
//return object set to default state if no match is found
let doc_obj = {bool: false, id: ""};
alert("Entering the match checker...");
for(let i =0; i<result.total_rows; i++) {
if(result.rows[i].doc.name == name){
alert(result.rows[i].doc.name);
alert(name);
doc_obj.bool = true;
doc_obj.id = result.rows[i].doc._id;
//found a match
break;
}
}
//return the result
alert("returned obj.id: "+doc_obj.bool);
return doc_obj;
}).catch(function (err) {console.log(err);});
};
Ideally, I would like the doc_obj or some return value object to be populated with data from the nameExists function, before evaluating my 'if statements'. How can I format my promise/resolve statement to achieve this?
You should drop that new Promise - it doesn't change anything about whether you will be able to wait for nameExists' result or not. You will need to return the promise that then() creates inside the nameExists function:
function nameExists(name) {
return localDB.allDocs({include_docs: true}).then(function (result) {
//^^^^^^
for (let i =0; i<result.total_rows; i++) {
if (result.rows[i].doc.name == name){
return {bool: true, id: result.rows[i].doc._id};
}
}
return {bool: false, id: ""};
});
// ^ don't catch errors here if you cannot handle them and provide a fallback result
}
Then you can just wait for it in your event listener:
document.getElementById("config-select").addEventListener("input", function() {
const doc_select = document.getElementById("config-select");
const doc_name = doc_select.value;
// check if the doc name exists: returns doc id
nameExists(doc_name).then(function(doc_obj) {
//^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^
console.log("then", doc_obj);
if (doc_obj.bool) { // it does exist:
alert("replacing id");
} else { // it doesn't:
alert("resetting id");
}
doc_select.setAttribute("doc-id", doc_obj.id); // id is "" when it doesn't exist
}).catch(function (err) {
console.log(err);
})
});
the only async call you have is inside the nameExists function which is the database call so there is no need to write two promises, only one is enough to solve your issue.
the first event should be like that:
document.getElementById("config-select").addEventListener("input", function(){
nameExists(doc_name).then(function(doc_obj) {
alert("then: "+doc_obj);
if(doc_obj.bool === true){//it does exist:
alert("replacing id");
document.getElementById("config-select").setAttribute("doc-id", doc_obj.id);
}
else{//it doesn't:
alert("resetting id");
document.getElementById("config-select").setAttribute("doc-id", "");
}
}).catch(function (err) { console.log(err) });
});
and the nameExists function should look like that:
//check if the name in config-select is an existing doc (assumes name is a unique document field)
const nameExists = function(name){
//get all docs
return localDB.allDocs({include_docs: true}).then(function (result) {
//return object set to default state if no match is found
let doc_obj = {bool: false, id: ""};
alert("Entering the match checker...");
for(let i =0; i<result.total_rows; i++) {
if(result.rows[i].doc.name == name){
alert(result.rows[i].doc.name);
alert(name);
doc_obj.bool = true;
doc_obj.id = result.rows[i].doc._id;
//found a match
break;
}
}
//return the result
alert("returned obj.id: "+doc_obj.bool);
return(doc_obj); // here is where the code runs then statement inside the event
});
};

Passing a variable between functions using jQuery

I am having trouble passing a variable from one function to another.
This code is from a PhoneGap app that I am working on, the idea is a QR code gets scanned using the offlineScan function which calls checkforOfflineTicket to check the local storage for ticket validation and returns the variable ticketCheck to determine whether the ticket is accepted.
My code below:
function checkforOfflineTicket(ticketID){
var ticketCheck = '1';
db = openDatabase(shortName, version, displayName,maxSize);
db.transaction(function(transaction) {
transaction.executeSql('SELECT * FROM tickets where ticketid=(?)', [ticketID],
function(transaction, result) {
if (result.rows.length == '1') {
if(result.rows.item(0)['status'] == '0'){
ticketCheck = 'OK';
}
else if(result.rows.item(0)['status'] == '1'){
ticketCheck = 'DUPLICATE';
}
else{
ticketCheck = 'ERROR';
}
}
else{
ticketCheck = 'NONE';
}
alert('the ticket check is '+ticketCheck);
},function(transaction, error) {
console.log("Error processing SQL: "+error.message);
});
},errorHandler,nullHandler);
return ticketCheck;
};
function offlineScan(){
cordova.plugins.barcodeScanner.scan(
function (result) {
if(!result.cancelled){
if(result.format == "QR_CODE"){
var ticketCheck = 'test';
var ticketID = result.text; // The ticketID is the full url
values=ticketID.split('='); // Split it at = to get the tickethash
one=values[0]; // url
two=values[1]; // hash
ticketCheck = checkforOfflineTicket(two);
alert('ticket check should be '+ ticketCheck);
} // End if result is QR
}
},
function (error) {
alert("Scanning failed: " + error);
}
);
}
The checkforOfflineTicket function is currently returning the alert the ticket check is OK and then second alert in the offlineScan function returns ticket check should be undefined. I have tried returning the variable in different places but no matter where I put it it does not get passed to the offlineScan function.
What am I missing? Thank you for any help!
This is caused by asynchronous method calls in your code. In checkforOfflineTicket the function to fetch the result set and doing the alert is called asynchronously to your offlineScan function. You have to chain your functions to get the correct order of execution. Following shows one possible way of chaining:
function checkforOfflineTicket(ticketID, callback) {
var ticketCheck = '1';
db = openDatabase(shortName, version, displayName,maxSize);
db.transaction(function(transaction) {
transaction.executeSql('SELECT * FROM tickets where ticketid=(?)', [ticketID],
function(transaction, result) {
...
alert('the ticket check is '+ticketCheck);
if (callback) callback();
}, ...
}
}
function offlineScan(){
cordova.plugins.barcodeScanner.scan(
function (result) {
if(!result.cancelled){
if(result.format == "QR_CODE"){
...
ticketCheck = checkforOfflineTicket(two, function() {
alert('ticket check should be '+ ticketCheck);
);
} // End if result is QR
}
},
function (error) {
alert("Scanning failed: " + error);
}
);
}

Function undefined when assigned to variable

I'm working on some authentication in React using Firebase as the backend.
I have a function to check if a user exists that works as I expect:
checkIfUserExists(uid) {
ref.child('users').child(uid).once('value', function(snapshot) {
if (snapshot.exists()) {
console.log("User exists");
return true;
} else {
console.log("User does not exist");
return false;
}
});
}
When I call it passing a uid, it will write to the console if the user exists or not.
this.checkIfUserExists(userId);
I want to just get a boolean representation of whether the user is logged in or not, but trying to do something like this will always print "No user".
if (this.checkIfUserExists(userId)) {
console.log('The user does really exist');
} else {
console.log('No user');
}
If i try to
console.log(this.checkIfUserExists(userId));
The console outputs "undefined".
Am i approaching this the wrong way? Why is it undefined?
The return statement inside the inner function will not return the value through the outer function. Instead try sending a function like this
checkIfUserExists(uid, callback) {
ref.child('users').child(uid).once('value', function(snapshot) {
callback.call(null, snapshot.exists());
});
};
checkIfUserExists(uid, function(exists){
if(exists){
console.log("User exists");
}else{
console.log("User does not exist");
}
});
More on .call() here in documentation

Parse.com Cloud Code - Creating new Instance of another object on before save

I have two classes, Groups and memberships. When a group is made, I'd like its corresponding membership to be made as well. I attempt to do so like this:
Parse.Cloud.beforeSave("Group", function(request, response) {
var name = request.object.get("name");
if (!name) {
response.error("A Group must have a name");
} else {
if (!(/^\w+$/i.test(name))){
response.error("Only letters and numbers, please.");
}
var query = new Parse.Query("Group");
query.equalTo("name", name);
query.first({
success: function(object) {
if (object) {
response.error("A group with this name exists.");
} else {
createMembershipForGroup(request.object, Parse.User);
response.success();
}
},
error: function(error) {
response.error("Could not validate Uniqueness");
}
});
}
});
createMembershipForGroup = function(group, user) {
var MembershipClass = Parse.Object.extend("Membership");
var membership = new MembershipClass();
membership.set("group", group);
membership.set("user", user);
membership.save(null,{
success:function(membership) {
response.success(membership);
},
error:function(error) {
response.error(error);
}
});
}
I receive an error back, saying the following:
E2014-05-06T21:40:10.740Z] v30: before_save triggered for Group for
user xgzDnZ9h0A Input:
{"original":null,"update":{"admin":{"objectId":"xgzDnZ9h0A","className":"_User","__type":"Pointer"},"name":"test","public":false}}
Result: undefined
Not too sure what the error is. How could I go about debugging code like this so I can isolate the issue easily?
Let beforeSave handle only the validation, and move your membership code to afterSave. The problem is probably that you're trying to store a relation to an object that is not yet saved (as you're in beforeSave, the object does not yet have an objectId)
problem is you are trying to call an async function and leaves before wait to complete it.
createMembershipForGroup(request.object, Parse.User);//Calling async func
response.success();//Leaves beforeSave function
You should write your createMembershipForGroup function inside success response of your query and return your response.success() method in here
membership.save(null,{
success:function(membership) {
response.success(membership); // this should be response of beforeSave
},
error:function(error) {
response.error(error);
}
});
I will post working code if this not helps.

JavaScript scope issue

I have the following piece of javascript but for some scoping reason the "names" that is returned from myfunc is empty.
var myfunc = function(client, id) {
var names = new Array();
client.query(
'SELECT stuff FROM mytable WHERE id="'+id+'"',
(function selectCb(err, results, fields) {
if (err) {
throw err;
}
for (result in results) {
// This prints fine
console.log(results[result].name);
names[result] = results[result].name;
}
client.end();
})
);
// The following returns empty
return names;
}
console.log(myfunc(1,2));
How can I make it break out of scope?
It's empty because the call to your "query" function is asynchronous. The function you pass into it won't be run until the results are available. Therefore, your "myfunc" function returns immediately, long before that callback function is invoked.
Using Javascript in a browser, you have to think in those terms. Instead of expecting your "names" to be ready immediately, change "myfunc" so that you pass it a callback function to be invoked when the names are actually available:
var myfunc = function(client, id, whenFinished) {
var names = new Array();
client.query(
'SELECT stuff FROM mytable WHERE id="'+id+'"',
(function selectCb(err, results, fields) {
if (err) {
throw err;
}
for (result in results) {
// This prints fine
console.log(results[result].name);
names[result] = results[result].name;
}
client.end();
if (whenFinished) whenFinished(names); // callback
})
);
};
Now when you call your function, instead of expecting the "names" as a return value, you'll pass in another function that will act on the list of names:
myfunc(1, 2, function(names) { console.log(names); });
If client.query(...) is asynchronous, then the selectCb function would not have run and names would not have changed by the time myfunc returns. You need to redesign myfunc to return names asynchronously (by, for example, accepting a function parameter which it calls at the end of selectCb).
var names = new Array();
var myfunc = function(client, id) {
client.query(
'SELECT stuff FROM mytable WHERE id="'+id+'"',function selectCb(err, results, fields)
{
if (err) {
throw err;
}
for (result in results) {
// This prints fine
console.log(results[result].name);
names[result] = results[result].name;
}
client.end();
}
);
// The following returns empty
return names;
}
console.log(myfunc(1,2));
try making names global

Categories

Resources