Phonegap db.transaction callback firing more than once - javascript

I am having an issue with a project I am working on using phonegap
[Step 1] -
I am storing a users login "session" locally (Web SQL) from a web server. This is working fine, I can successfully connect to the web server, post the user login data, get a response from the server, create the local User database and store the user "session" value
[Step 2] - I then need to pass this "session" value back to the web server, and receive response data from the server. Again, this works as expected but the problem is, the callback function is being executed twice.
Step 2 is called when the user taps a button on the screen, and it doesn't seem like the reason that Step 2 is being called twice if because phonegap is picking up the tap more than once, I have tried:
$(".yes_sync").live("tap", function(){
console.log("tap!");
...
Which only logs a single tap event.
When the user taps I am calling:
var db = window.openDatabase("MVIdb", "1.0", "MVIsqlite", 200000);
db.transaction(getUserId, getUserIdFailed, getUserIdsSuccess);
The getUserId, getUserIdFailed and getUserIdsSuccess functions look like so:
function getUserId(tx){
tx.executeSql("SELECT * FROM user WHERE id = '1'", [], getUserIdsSuccess, getUserIdFailed);
}
function getUserIdFailed(tx, results){
console.log("Error retrieving user session ID");
}
function getUserIdsSuccess(tx, results){
console.log("Success retrieving user session ID");
if(typeof results != 'undefined'){
var return_value = results.rows.item(0).user_id;
user_session_id = return_value;
var token = $.md5(user_session_id+"whatever!");
$.get('http://localhost/project/dummyserver/sync?user_id=' + user_session_id + '&token=' + token, function(data) {
data = $.parseJSON(data);
for (var key in data){
console.log(data[key]['user_id']);
}
$(".ui-loader").fadeOut();
jQuery.mobile.changePage("_sync_complete.html", { role: "dialog", transition: "pop" } );
});
}
}
As you can see, the last line in the callback for the $.get in the callback for the success opens a pop up dialogue. This dialogue is being called twice.
I have noticed that phonegap has a lot of asynchronous behaviour, which I understand is to prevent the system from feeling "laggy", but surely it shouldn't be executing a callback function on a db.transaction more than once?

Your callback is called twice because you are passing it both to the executeSql command and the transaction. Remove it from one to make it work as expected.

Not the most elegant solution, but I went with using a global variable
var has_getUserIdsSuccess = false;
And in the callback function:
if(typeof results != 'undefined'){
if (has_getUserIdsSuccess == false){
has_getUserIdsSuccess = true;
// as per above
has_getUserIdsSuccess = false; // set it back to false so use can press the execute this function again later
}
I am still interested to see if anyone has a better solution!

Related

How to update value instead of restarting the app

I have this piece of code in my iOS app inside WebViewController.swift:
var pushIDOneSignal = userID
if pushIDOneSignal == nil
{
// do nothing
}
else
{
webviewurl += pushIDOneSignal! //Add PushID token to the URL
}
I'm using pushIDOneSignal to get the playerid for the user. The problem is when the user opens the app the first time, we get a nil value; because has to accept permission notifications first.
Somehow I managed to create a way to get the playerid, but it only works if the user accepts the notifications and then, closes the app, and opens again.
How can I make the app try to read this again: if pushIDOneSignal == nil after the user has accepted notifications? Then that time, will get the else condition and then we will get the playerid.
Edit:
I have idea-
if pushIDOneSignal == nil
{
// do nothing
}
else
{
webviewurl += pushIDOneSignal! //Add PushID token to the URL
}
How i can make keeps looping when value is nil? Thanks.

javascript "callbacks" across redirecting / after reloading

I've got a site (asp.net mvc razor) on wich some functionalities require authorization / login.
These functionalities can be started by clicking on a button for example.
By clicking on such a button, the system checks whether the user is logged in or not.
If not, the user is redirected to the login page where he can sign in.
After that he will be redirected to the initial page again without initiating the users action.
So heres the workflow:
->Page x -> button y -> click -> redirect to login -> login -> redirect to x.
The redirects are simple Url.Action() statements.
What I want to do is to dynamically redirect to the page the click came from and ideally jump to the senders selector in order to simplify things for users.
What possibilities do I have to achieve this?
Only things coming to my mind are quite ugly stuff using ViewBag and strings
Update:
Info: As storing session variables causes problemes concerning concurrent requests this feature is disabled solution wide so I cannot use session variables.
Besides: One of the main problems is, that I cannot sign in without making an ajax call or sending a form. And by sending a form or making an ajax call I loose the information about the original initiator of the action and the parameters.
I solved this by adding by adding this to all such actions in their controllers:
[HttpPost]
public ActionResult ActionA(Guid articleId, Guid selectedTrainerId)
{
//if user is not authenticated then provide the possibility to do so
if (!Request.IsAuthenticated)
{
var localPath = this.ControllerContext.RequestContext.HttpContext.Request.Url?.LocalPath;
var parameter = this.ControllerContext.RequestContext.HttpContext.Request.Params["offeringRateId"];
var returnUrl = localPath + "?articleId=" + parameter;
return PartialView("LoginForOfferingPreview", new LoginForOfferingPreviewViewModel
{
RequestUrl = returnUrl,
//this will be used in the view the request was initiated by in order to repeat the intial action (after login has been successfull)
Requester = OfferingPreviewRequester.CourseTrialAdd,
//this will be used in the view to initiate the request again
RequestParameters = new List<dynamic> { new { articleId = articleId },new { selectedTrainerId = selectedTrainerId }}
});
}
//actual action
SendBasketEvent(new CourseAddMessage
{
BasketId = BasketId,
OfferingRateId = articleId,
SelectedTrainerId = selectedTrainerId,
SelectedTime = selectedTime,
Participants = selectedParticipants,
CurrentDateTime = SlDateTime.CurrentDateTimeUtc(SlConst.DefaultTimeZoneTzdb),
ConnectionId = connectionId
}, connectionId);
return Json(JsonResponseFactory.SuccessResponse());
}
the hereby returned view for login contains following js code that is called if the login has been succesfull:
function onLoginFormSubmit(data) {
//serialize form containing username+pw
var datastring = $("#loginForm").serialize();
$.ajax({
type: "POST",
url: '#Url.Action("Login_Ajax","Account",new {area=""})',
data: datastring,
success: function (data) {
debugger;
// display model errors if sign in failed
if (!!!data.Success) {
$(".buttons-wrap").append('<span id="loginFormError" style="color:red;"></span>');
$("#loginFormError").append(data.ErrorMessage);
}
//call method of initiating view that will decide what to dow now
if (data.Success) {
var parametersObjectAsString = JSON.parse('#Html.Raw(JsonConvert.SerializeObject(Model.RequestParameters))');
window.onLoginForOfferingPreviewSuccess('#Model.RequestUrl', parametersObjectAsString, '#((int)Model.Requester)');;
}
},
error: function () {
}
});
}
this works fine as long sigining does not fail due to wrong username or pw.
If that happens, the view shows the errors but by now signing in again somethign really strange happens:
At first it seems to work exaclty like signing in successfully by the first time but then the ajax calls in window function onLoginForOfferingPreviewSuccess will always reach the error block without beeing able to tell you why.
Fiddler reveals weird http resonse codes like 227,556 or something
Thx

Updating data from Parse.com without re-login

I have a web app, that manages a budget for a user.
In the settings page, I can edit the budget, after clicking "save" I return to the main page, and there I have line that states the budget amount.
The problem is, that when I log in, I see the correct budget, after editing the budget and returning to the main page, I still see the old amount. Only after logging out and re-login again, that line in the main page updates to new amount.
Any solutions?
The code that saves the new budget:
$("#saveNewBudgetAmount").click(function(){
var User = Parse.User.extend("User");
var query = new Parse.Query(User);
var newBudget = $("#newBudgetSum").val();
query.equalTo("objectId", Parse.User.current().id);
query.first({
success: function (User) {
User.save(null, {
success: function (user) {
User.set("budget", newBudget);
User.save();
location ="Mainpage.html";
}
});
}
});
});
and the code that displays it on the main page:
var MBudget = (function () {
if (Parse.User.current()) {
return("Your monthly budget is:" +" "+Parse.User.current().get("budget")+" "+"<a href=Settings.html>(Edit)</a>");
}
A few things are happening.
First you should simplify your code, and use both alerts AND error handling so that you know if your code works, and when callbacks are made. You are also calling .save() once before any new values are set, so you have a useless save.
You also need to have a success and error callback for EVERY save function you use - .save() by itself is an asynchronous method, and since you are not calling a success function within your save method, so your app will navigate back to "Mainpage.html" before it is known whether or not the save function worked. Here is a much better implementation:
var newBudget = $("#newBudgetSum").val();
var currentUser = Parse.User.current();
currentUser.save(
{
// Set as many properties as you like in this field,
// think of it as a JSON object except you don't
// have to enclose the values in strings.
budget : newBudget,
}, {
success: function(user) {
alert("Budget successfully saved, new budget is: " + user.get("budget"));
},
error: function(error) {
// error functions will always have an error argument handed back to the client,
// with properties error.code and error.message. Error messages are incredibly useful.
alert("Budget save failed, error: " + error.code + " " + error.message);
}
});
Another tip is that I recommend all users of Parse.com to use alert() messages for their success and error callbacks while in development, for many reasons - but the key reasons are 1) it will alert you to whether or not the code worked, and 2) it will prevent accidental bugs from causing infinite requests to the Parse.com server, which does happen sometimes, and will cause them to charge your account.
The problem is this api : Parse.User.current() never sync data in the cloud. The data of Parse.User.current() is derived from localstorage. You have to refresh it manually by calling save or fetch method on it.
Parse.User.Current() return normal Parse.User object. You can use it directly without querying in advance. So you can just rewrite your first codes as following :
$("#saveNewBudgetAmount").click(function() {
var user = Parse.User.current() ;
var newBudget = $("#newBudgetSum").val();
user.set("budget", newBudget);
user.save(null,{
success: function(user) {
// feedback user and redirect page.
},
error: function(user, error) {
//You should always handle error.
console.error(error.message) ;
}
}) ;
});
With this code, the local data would refresh when ths save() call done successfully. On your main page the budget value of Parse.User.current() object would be correct.

Phonegap/Cordova query Web SQL Database

I'm developing an Android/iOS mobile application using cordova/phonegap.
When my app is ready, It's going to create, if needed, the database (DB) using Web SQL.
After creation, I'm going to make a DB query to know whether a user already exists in DB or not. Depending on query result, I will either show a form to user or simply present a welcome message.
DB Initialization code (when application is ready):
app.db.transaction(app.initDB, app.dbError, app.queryUser);
If previous code runs ok, the funcion app.queryUser gets executed:
app.queryUser = function(tx){
tx.executeSql('SELECT name, mail from User', [], app.renderUserData, app.dbQueryError);
}
And my function app.renderUserData:
app.renderUserData = function(tx, results){
if(results.rows.length < 1) {
console.log("You have NO data!");
inputUserData();
} else {
console.log("You have data!");
showUserData(results.rows.item(0).name, results.rows.item(0).mail);
}
}
Inside this function, depending on whether user has associated data or not on DB, I'm going to call one of two functions that injects some HTML DOM on the page.
In the middle of any of these functions - inputUserData() or showUserData() - sometimes (seems like it's random) the code just stops executing, and calls the error callback function app.dbError() (from my app.db.transaction call) gets called with following message:
"the statement callback raised an exception or statement errorcallback did not return false"
And it just happens while I'm testing this on my Android phone, because when using the app on Chrome dev tools, or using Apache Ripple the app does what it's supposed to do.
If someone needs more info about the code, etc, just ask..
Thanks in advance for the help.
EDIT
There is app.dbQueryError()
app.dbQueryError= function(err){
console.log("QUERY ERROR: " + err.message + "\nCode=" + err.code);
}

Storing data from elements before a refresh

I have a web page with 3 elements where a user will enter a text value and then press a button. On submit, it will process and return some values to be populated in a table.
This part works fine.
Now if the user refreshes the page, all the data is gone and the 3 elements and the table looks empty.
I would like to do this. Catch the refresh event and store the 3 user entered values in a local storage and when the page is loading back up, I will send this back to the controller to populate the tables again.
Is this possible to do? I am pretty new to web development and am running out of ideas.
This is what I tried. And this doesn't work.
window.onbeforeunload = function() {
localStorage.setItem(name, $('#name_field').val());
localStorage.setItem(id, $('#id_field').val());
localStorage.setItem(pw, $('#pw_field').val());
alert("am here")
}
window.onload = function() {
var name= localStorage.getItem(name);
if (name != null) $('#name_field').val(name);
var id= localStorage.getItem(id);
if (id!= null) $('#id_field').val(id);
var pw= localStorage.getItem(pw);
if (pw!= null) $('#pw_field').val(pw);
}
I could never get the alert in window.onbeforeunload function to pop up.
You can store it everytime on the local storage(or event session storage, which I think its better in your case). Then everytime you look after that value on the storage. In case of any value found, you send it to the controller.
If it was me I would do as I said above, save your data into the sessionStorage(what means that the data will be lost if user closes the tab/browser):
var saveData = function()
{
var data =
{
id: $("#id_field").val(),
name: $("#name_field").val(),
pw: $("#pw_field").val()
};
sessionStorage.setItem("formValues", JSON.stringify(data));
}
Idk if your post is async or not. If its async, you can call that function on your successCallback, if it isn't async, call it on the submit event.
Then at ready event, you can read that data:
$(document).ready(function()
{
var data = sessionStorage.getItem("formValues");
// Check if there is any user data already saved
if (data)
{
data = JSON.parse(sessionStorage.getItem("formValues"));
$("#id_field").val(data.id);
$("#name_field").val(data.name);
$("#pw_field").val(data.pw);
}
});
I prefer to store a group of data in an object into a single key on the storage, that is why I use JSON to stringify and parse an object, because storage only accepts string types.
A simple advise: Don't - ever - store passwords, let the user type it. For security reasons.

Categories