I've looked at this How-do-i-return-the-response-from-an-asynchronous-call and at why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron , but what I'm trying to do doesn't work.
Since some of our users use IE, it seems that we would have to rely on callbacks.
The background to this question comes from a previous post. Legacy code used VBscript's MsgBox, but now the same functionality must be ported to Javascript.
To provide context, there is a bunch of buttons on a toolbar (hence toolbar.asp) such as "New", "Update", "Delete". The user can navigate to certain parts of the system and for instance create a "New" record for a particular resource/person. The details and functionality are shown on the main part of the screen (hence main.asp).
The system was originally written about 15 years ago (or more).
When the user clicks "Update" on the toolbar.asp, it depends which screen the main.asp was showing. Parts of dovalidation() in main.asp can be swopped (as in a script is fetched from the database) and inserted into dovalidation() depending on what & where the user is.
So some parts are still in Visual Basic 6, but it seems that they are trying to replace the VBscript with Javascript.
So the user is on a specific screen and clicks Update (the toolbar.asp's doupdate() is called).
This doupdate() does a number of checks on the date and other variables and the calls the main.asp's dovalidation().
Depending on where the user finds himself, dovalidation looks different.
In quite a few cases as in the specific example that I am talking about, there used to be a MsgBox in the VBscript code which gave the user a choice depending on the validation done up to that point. However, that VBscript should now be replaced by Javascript. It seems my boss doesn't want to use the normal window.confirm, because she wants to be able to customise the buttons.
VBscript's MsgBox blocked further execution, but now using a jquery confirm doesn't have the same results, because it is non-blocking.
If the validation occurs in such a way that the user is provided with the confirm dialog, and the user clicks on 'Cancel' then the next page should not be shown, but at present, whether the user clicks on 'Cancel' or not, the next page is shown after a couple of seconds.
At the end of the doupdate() function there is:
parentMain.screenform.submit();
Could that be part of why my callbacks don't work?
In a toolbar.asp file, this is called in the doupdate() funtion:
//... Other code that determines variables, fringe scenarios etc.
//...
// Then dovalidation() (in which the blocking MsgBox used to be) is called:
var sErr = parentMain.dovalidation();
if (sErr != ""){
return;
}
//Then the rest of the code which is executed irrespective of the jquery confirm.
//do update
try {
parentMain.document.all("Updating").value = "YES"
parentMain.document.body.scrollTop = 0
parentMain.document.body.scroll = 'no'
parentMain.ShowBusy();
document.getElementById("sysBusy").value = "true";
//parentMain.document.all("clockFrame").style.display = "block";
} catch(e) {
return (e)
}
//do check for resource tag
if (sScreenType.toUpperCase() == "RESOURCE TABLE") {
if (lResource == "0") {
parentMain.document.all("sysresource").value = lDetailResource
}
//alert("looping for resource tag");
var sField = ""
var sCheck = "Resource Tag"
if (!(sScreen == "Resource")) {
/*********************************************************************/
/** loop through the fields and update resouce tag if empty - submit**/
/*********************************************************************/
var elements = parentMain.document.getElementById("screenform").elements;
for (var i = 0, element; element = elements[i++];) {
if ((element.name).indexOf(sCheck) > 0) {
var sValue = element.value
if (sValue.length == 0) {
element.value = lDetailResource
}
}
if ((element.tagName.toUpperCase()) == "SELECT") {
if (element.disabled == true) {
element.disabled = false;
}
}
}
}
}
//submit screen
parentMain.screenform.submit(); //<-- Could this be part of the problem?
}
In the main.asp file the dovalidation function resides. A part of the dovalidation function is swapped out depending on the situation. That is marked between the //################
function dovalidation() {
msErr = "";
//#################
if (msErr.length == 0) {
var vEffectiveDate="";
var vLastRunDate="";
var sStatus="";
var vMsg="";
var sResponse="";
vEffectiveDate = document.getElementById("Smoke.Effective Date").value;
vLastRunDate = document.getElementById("Smoke.Last Run Date").value;
sStatus = document.getElementById("Smoke.Calc Status").value;
vMsg = "";
if ((sStatus).length == 0 ){
sStatus = "SUCCESFUL";
//document.getElementById("Smoke.Calc Status").value= sStatus;
}
if ((vEffectiveDate).length > 0 ){
if (!isDate(vEffectiveDate) ){
vMsg = vMsg+"[Effective Date] Is not a date." + ";\r\n";
} else if ( moment( toDate(vEffectiveDate)).isBefore(toDate(vLastRunDate)) ){
vMsg = vMsg+"[Effective Date] cannot be on/before "+vLastRunDate+"." + ";\r\n";
}
}
if (sStatus.toUpperCase() != "SUCCESFUL") {
$.confirm({
title: "Confirmation",
columnClass: 'col-md-6 col-md-offset-3',
content:"Forecast calculation still busy. Results might not be accurate. Continue?",
buttons: {
confirm: function() {
sResponse= "1";
vMsg = "Response 1";
processMessage(); // <--- added this
},
cancel: function() {
sResponse= "2";
vMsg = "Response 2";
// Moved code here, as it needs to execute when Cancel is clicked
$.alert({
title: "INFORMATION",
columnClass: 'col-md-6 col-md-offset-3',
content: "Screen will refresh. Please click on Update to try again.",
// Code that should execute when alert is closed:
onAction: function () {
document.getElementById("Smoke.Calc Status").value= "REFRESH";
msErr = "ABORT";
processMessage(); // <--- added this
}
});
},
}
});
} else { // <-- added
processMessage();
}
function processMessage() {
// Moved code in a function, as it should only execute after confirm/alert is closed
if (vMsg != "") {
$.alert({
title: 'Validation Message',
columnClass: 'col-md-6 col-md-offset-3',
content: vMsg,
});
msErr = "ERROR";
}
}
}
//#################
return msErr;
}
So I think my problem lies with msErr being returned long before the user has had chance to decide which button on the confirm dialog to choose. If I don't set breakpoints and click on the confirm's cancel then I do see that the alerts are shown, but the page is not refreshed (document.getElementById("Smoke.Calc Status").value= "REFRESH";) and the next page is shown. I think this comes from the sErr == "" in the toolbar.asp file and then the program flow just continues.
Anycase, I tried using callbacks, but the situation hasn't changed.
Here is what I tried to do:
parentMain.dovalidation(function(result){
if (result != ""){
return;
}
});
In main.asp the dovalidation function:
function dovalidation(callback) {
msErr = "";
//#################
if (msErr.length == 0) {
var vEffectiveDate="";
var vLastRunDate="";
var sStatus="";
var vMsg="";
var sResponse="";
vEffectiveDate = document.getElementById("Smoke.Effective Date").value;
vLastRunDate = document.getElementById("Smoke.Last Run Date").value;
sStatus = document.getElementById("Smoke.Calc Status").value;
vMsg = "";
if ((sStatus).length == 0 ){
sStatus = "SUCCESFUL";
document.getElementById("Smoke.Calc Status").value= sStatus;
}
if ((vEffectiveDate).length > 0 ){
if (!isDate(vEffectiveDate) ){
vMsg = vMsg+"[Effective Date] Is not a date." + ";\r\n";
} else if ( moment( toDate(vEffectiveDate)).isBefore(toDate(vLastRunDate)) ){
vMsg = vMsg+"[Effective Date] cannot be on/before "+vLastRunDate+"." + ";\r\n";
}
}
if (sStatus.toUpperCase() != "SUCCESFUL") {
$.confirm({
title: "Confirmation",
columnClass: 'col-md-6 col-md-offset-3',
content:"Forecast calculation still busy. Results might not be accurate. Continue?",
buttons: {
confirm: function() {
sResponse= 1;
vMsg = "Response 1";
processMessage(); // <--- added this
},
cancel: function() {
sResponse= 2;
vMsg = "Response 2";
// Moved code here, as it needs to execute when Cancel is clicked
$.alert({
title: "INFORMATION",
columnClass: 'col-md-6 col-md-offset-3',
content: "Screen will refresh. Please click on Update to try again.",
// Code that should execute when alert is closed:
onAction: function () {
document.getElementById("Smoke.Calc Status").value= "REFRESH";
msErr = "ABORT";
processMessage(); // <--- added this
}
});
},
}
});
} else { // <-- added
processMessage();
}
function processMessage() {
// Moved code in a function, as it should only execute after confirm/alert is closed
if (vMsg != "") {
$.alert({
title: 'Validation Message',
columnClass: 'col-md-6 col-md-offset-3',
content: vMsg,
});
msErr = "ERROR";
}
}
}
//#################
callback(msErr);
}
So, it isn't working as it should, and I don't know what I've done wrong, but I suppose I haven't used the callbacks correctly.
Does it make a difference that it is in two different files?
This has to work given that the parts between the //######### are swopped.
I would appreciate any feedback and guidance.
Well, ok. I started to write a comment, but it is too small for all I need to say, so I will continue in an answer.
I see you added some more code, but... you know, your code are blowing my mind =) what you are trying to do is to get spaghetti-code and make it async.
Throw this away and let's go to the upper level. We call it "program on an interface level".
Example: replace all your big code blocks with functions (with correct name). Like code between //################# will be converted to
function dovalidation(callback) {
msErr = getValidationResult();
callback(msErr);
}
What do I do here is just throw away all your low-level code, because your problem is in the order of execution.
But this is just the first step of converting your code to something other. Next step is realizing that our "virtual" function getValidationResult has some $.confirm and $.alert inside, so it is async. That's why we need to use getValidationResult as async. Two possible ways - convert to Promise or use callbacks. Let's use callbacks. Then our simplified code will convert to:
function dovalidation(callback) {
getValidationResult(callback);
}
That is what I was trying to show on my previous answer.
And now you've added some more code with such a comment: //Then the rest of the code which is executed irrespective of the jquery confirm.. Ok, good, we will name all this code as theRestOfTheCodeIrrespectiveToConfirm(). So your original function call will be converted from this:
//... Other code that determines variables, fringe scenarios etc.
//...
// Then dovalidation() (in which the blocking MsgBox used to be) is called:
var sErr = parentMain.dovalidation();
if (sErr != ""){
return;
}
theRestOfTheCodeIrrespectiveToConfirm();
to this:
//... Other code that determines variables, fringe scenarios etc.
//...
// Then dovalidation() (in which the blocking MsgBox used to be) is called:
parentMain.dovalidation(sErr => {
if (sErr != ""){
return;
}
theRestOfTheCodeIrrespectiveToConfirm(); // <- this will execute only if sErr is empty
});
Am I going to the right direction?
P.S. One thing to ask you - why do you have } in the end of you example code, but no correcsponding {?
Maybe you show us not all code?
There is no need to involve jQuery.
JavaScript has the functions alert, confirm and prompt which are synchronous (i.e. blocking execution until they return) just like MsgBox was.
So if this is easier to you, you can keep your original code structure this way. Because as it was explained in the "how do I return a response from an asynchronous call" article, you cannot make the dovalidation function return anything that depends on the result of an asynchronous operation like the $.confirm that you currently use, since that would require time travel ;) - but you can make it dependent on synchronous operations like JS' built-in confirm.
You are mixing sync code with async... Because $.confirm is async, but you call dovalidation as sync.
Note: your code is very strange, maybe because of small JS experience, so I will try to guess what you need. You can ask if something in my code is incorrect.
Your second example with callback is more close to working solution, but you need to call the callback only if you know the user's answer.
So let's change your code a bit. Extract processMessage function (now it is async) and call processMessage with correct parameters:
function processMessage(vMsg, msErr, callback) {
// Moved code in a function, as it should only execute after confirm/alert is closed
if (vMsg) {
$.alert({
title: 'Validation Message',
columnClass: 'col-md-6 col-md-offset-3',
content: vMsg,
});
msErr = "ERROR";
}
callback(msErr); // <-- return result
}
function dovalidation(callback) {
var vMsg = "", msErr = "";
//#################
if (msErr.length == 0) {
var vEffectiveDate = "";
var vLastRunDate = "";
var sStatus = "";
var sResponse = "";
vEffectiveDate = document.getElementById("Smoke.Effective Date").value;
vLastRunDate = document.getElementById("Smoke.Last Run Date").value;
sStatus = document.getElementById("Smoke.Calc Status").value;
vMsg = "";
if ((sStatus).length == 0) {
sStatus = "SUCCESFUL";
document.getElementById("Smoke.Calc Status").value = sStatus;
}
if ((vEffectiveDate).length > 0) {
if (!isDate(vEffectiveDate)) {
vMsg = vMsg + "[Effective Date] Is not a date." + ";\r\n";
} else if (moment(toDate(vEffectiveDate)).isBefore(toDate(vLastRunDate))) {
vMsg = vMsg + "[Effective Date] cannot be on/before " + vLastRunDate + "." + ";\r\n";
}
}
if (sStatus.toUpperCase() != "SUCCESFUL") {
$.confirm({
title: "Confirmation",
columnClass: 'col-md-6 col-md-offset-3',
content: "Forecast calculation still busy. Results might not be accurate. Continue?",
buttons: {
confirm: function() {
sResponse = 1;
vMsg = "Response 1";
processMessage(vMsg, msErr, callback); // <--- added this
},
cancel: function() {
sResponse = 2;
vMsg = "Response 2";
// Moved code here, as it needs to execute when Cancel is clicked
$.alert({
title: "INFORMATION",
columnClass: 'col-md-6 col-md-offset-3',
content: "Screen will refresh. Please click on Update to try again.",
// Code that should execute when alert is closed:
onAction: function() {
document.getElementById("Smoke.Calc Status").value = "REFRESH";
msErr = "ABORT";
processMessage(vMsg, msErr, callback); // <--- added this
}
});
},
}
});
} else { // <-- added
processMessage(vMsg, msErr, callback); // <--- added this
}
}
//#################
}
Note: this code is not "clean". If this function dovalidation you showed us has full code, then you can clean the code. This code is runnable (better use it in fullscreen), but I still do not understand what you are trying to do...
const isDate = (x) => true; // Mock
const toDate = (x) => x; // Mock
function processMessage(mType, vMsg, msErr, callback, sResponse) {
if (vMsg) {
$.alert({
title: 'Validation Message',
columnClass: 'col-md-6 col-md-offset-3',
content: vMsg,
});
msErr = "ERROR"; // ???
}
callback(mType, msErr, vMsg, sResponse); // <-- return result
}
function dovalidation(callback) {
var sResponse = "";
let vMsg = '';
let msErr = '';
let vEffectiveDate = document.getElementById("Smoke.Effective Date").value;
let vLastRunDate = document.getElementById("Smoke.Last Run Date").value;
let sStatus = document.getElementById("Smoke.Calc Status").value;
if (!sStatus) {
sStatus = "SUCCESFUL";
document.getElementById("Smoke.Calc Status").value = sStatus;
}
if (vEffectiveDate) {
if (!isDate(vEffectiveDate)) {
vMsg = vMsg + "[Effective Date] Is not a date.;\r\n";
} else if (moment(toDate(vEffectiveDate)).isBefore(toDate(vLastRunDate))) {
vMsg = vMsg + "[Effective Date] cannot be on/before " + vLastRunDate + ".;\r\n";
}
}
if (sStatus.toUpperCase() != "SUCCESFUL") {
$.confirm({
title: "Confirmation",
columnClass: 'col-md-6 col-md-offset-3',
content: "Forecast calculation still busy. Results might not be accurate. Continue?",
buttons: {
confirm: () => {
sResponse = 1;
vMsg = "Response 1";
processMessage('Confirm', vMsg, msErr, callback, sResponse);
},
cancel: function() {
sResponse = 2;
vMsg = "Response 2";
$.alert({
title: "INFORMATION",
columnClass: 'col-md-6 col-md-offset-3',
content: "Screen will refresh. Please click on Update to try again.",
// Code that should execute when alert is closed:
onAction: () => {
document.getElementById("Smoke.Calc Status").value = "REFRESH";
msErr = "ABORT";
processMessage('Abort', vMsg, msErr, callback, sResponse);
}
});
},
}
});
} else {
processMessage('Success', vMsg, msErr, callback, sResponse);
}
}
function test() {
dovalidation(function(mType, msErr, vMsg, sResponse) {
console.log('[TYPE]', mType, '[RESULT]', msErr || '?', '[MESSAGE]', vMsg || '?');
//if (result != "") {
// return;
//}
});
}
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-confirm/3.3.2/jquery-confirm.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-confirm/3.3.2/jquery-confirm.min.js"></script>
<input type="text" id="Smoke.Effective Date" value="2020-01-02"/>
<input type="text" id="Smoke.Last Run Date" value="2020-01-01"/>
<input type="text" id="Smoke.Calc Status" value="WTF?"/>
<button onclick="test()">TEST</button>
Related
Before customers can proceed to paypal, I have a quick check on the database to see if the items still available,. The problem im having is that while Ajax is executing. function check_availability continue executing and returns true to the Form onsubmit before the completion of Ajax. To fix that problem I kept calling the same function within. But I dont think that is the best possible option.
Here is the code:
<form onsubmit="return check_availability(0,0,1)" action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post" id="pp1">
function ajax_paypal(orders){
var htpr = new XMLHttpRequest();
var url = "Hi there";
var val = "orders="+orders;
htpr.open("POST", url, true);
htpr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
htpr.onreadystatechange = function(){
if(htpr.readyState == 4 && htpr.status == 200){
var sold_out_ids = htpr.responseText;
check_availability("continue", sold_out_ids, 0);
}
};
htpr.send(val);
}
function check_availability(str, sold_out_ids, n) {
if (str === "continue") {
if (sold_out_ids > 0) {
alert("One of your items has sold out! Sorry for any inconvenience");
location.reload();
return false;
} else {
return true;
}
}else if(n === 1){
var orders = [];
var x = document.cookie.split(';'); // your array of cookies
var i = 0;
x.forEach(item => {
//to make sure that item contains "order"
if (item.indexOf('order') > -1) {
var val = item.split("=");
orders[i] = val[1]+"o";
i++;
}
});
ajax_paypal(orders);
}
check_availability(0, 0, 0);//I keep calling this until Ajax is completed
}
You can use following code snippet to solve. This will be called on submit but before actual submit happen if you return true from here form will get submit to paypal. If you return false form won't get submit.
$('#pp1').submit(function() {
var submitOrNot=await callcheck_availability();
return true; // return false to cancel form submit
});
async function callcheck_availability(){
//your function goes here
}
for more on async await read this page on MDN
I have this script:
(function (exports) {
function valOrFunction(val, ctx, args) {
if (typeof val == "function") {
return val.apply(ctx, args);
} else {
return val;
}
}
function InvalidInputHelper(input, options) {
input.setCustomValidity(valOrFunction(options.defaultText, window, [input]));
function changeOrInput() {
if (input.value == "") {
input.setCustomValidity(valOrFunction(options.emptyText, window, [input]));
} else {
input.setCustomValidity("");
}
}
function invalid() {
if (input.value == "") {
input.setCustomValidity(valOrFunction(options.emptyText, window, [input]));
} else {
console.log("INVALID!"); input.setCustomValidity(valOrFunction(options.invalidText, window, [input]));
}
}
input.addEventListener("change", changeOrInput);
input.addEventListener("input", changeOrInput);
input.addEventListener("invalid", invalid);
}
exports.InvalidInputHelper = InvalidInputHelper;
})(window);
InvalidInputHelper(document.getElementById("firstname"), {
defaultText: "Please enter an firstname !",
emptyText: "Please enter an firstname!",
invalidText: function (input) {
return 'The firstnames "' + input.value + '" is invalid!';
}
});
and i have this textbox:
#Html.TextBoxFor(m => m.Register.FirstName, new { id = "firstname", #class = "form-control", #required = "required" })
But i get an error Cannot read property 'setCustomValidity' of null in console...what am i doing wrong? I see that is working here http://jsfiddle.net/B4hYG/437/ but for me its not...is it beacause of mvc or what?
That script, where in your code is it located? I'm guessing it's located in the header?
In your example, if you change the second drop-down at the top left to No wrap - in <head>, you get the error you described and you can see it being broken here.
This is because your elements haven't been created yet. Either you need to move your InvalidInputHelper function call to the bottom of the page so it runs after the elements are created, or you need to wrap it in a function to tell it to not fire until everything has run.
If you are definitely using jQuery you can wrap it with the ready function like so:
$('document').ready(function(){
InvalidInputHelper(document.getElementById("firstname"), {
defaultText: "Please enter an firstname !",
emptyText: "Please enter an firstname!",
invalidText: function (input) {
return 'The firstnames "' + input.value + '" is invalid!';
}
});
});
and here it is working.
Or if you prefer a pure JavaScript solution you can use the vanilla alternative found here.
To reiterate though, the easiest way would be to move the call to the bottom of the page, if you can.
i cannot "add a comment"... i reply here...
I think that the problem could be the 'document.getElementById("firstname")'.
You get it after the DOM is ready? (i don't know how MVC work)
Try to put your code:
InvalidInputHelper(document.getElementById("firstname"), {
defaultText: "Please enter an firstname !",
emptyText: "Please enter an firstname!",
invalidText: function (input) {
return 'The firstnames "' + input.value + '" is invalid!';
}
});
in document loaded function
(example for jquery:
$(function() { /* your code here */ }); )
In react you should use event.target.setCustomValidity
I have a web application that performs a Jquery .post request for database queries. I also have three different web socket connections that are used to push status updates from the server to the client (CPU and Memory stats in a live chart, database status, and query queue). While a query is not running, everything works smoothly, but once a query is started (post request), then the three web socket connections seem to hang/block while waiting for the query to return. I was reading about this and have not found any relevant answers...I suspect that it is probably something really dumb on my part...but this has had me scratching my head for the better part of a day now. I thought I might try moving the web socket connections to web workers...but in theory, the POST should not be blocking to begin with...So, here are the relevant snippets of code...The full source is a couple of thousand lines of code...so I didn't want to inundate anyone with it...but could show it if it is useful. So, the big question is what am I doing wrong here? Or perhaps, am I misunderstanding how AJAX calls work as far as blocking goes?
// query execution button that grabs the query for the most recently focused query source (SPARQL editor, history, or canned)
$("#querySubmitButton").on("click", function(e) {
// Disable the query button
$("#querySubmitButton").attr('disabled',true);
// Let's make sure we are clearing out the work area and the popup contents
$("#viz").empty();
// Get YASQE to tell us what type of query we are running
var queryType = editor.getQueryType();
// refactored so that we can clean up the on-click function and also make other query types in a more modular way
switch(queryType) {
case 'SELECT':
sparqlSelect();
break;
case 'CONSTRUCT':
sparqlConstruct();
break;
case 'ASK':
sparqlAsk();
break;
case 'DESCRIBE':
sparqlDescribe();
break;
case 'INSERT':
sparqlInsert();
break;
default:
popup.show("Unrecognized query type.","error");
break;
}
});
// Functions to do each of the query types (SELECT, CONSTRUCT, ASK, DESCRIBE, INSERT)
// SELECT
function sparqlSelect() {
$.post("sparqlSelect", { database: $("#DB_label").html(),'query': editor.getValue() }).done(function(data, textStatus, xhr) {
// Enable the query button
$("#querySubmitButton").removeAttr('disabled');
// If the query worked, store it
storeQueryHistory(query);
// if the previous query was a CONSTRUCT, then lets hide the graph metrics button
$("#nav-trigger-graphStatistics").fadeOut(800);
// Need to slide the query menu back
sliders("in",$("#nav-trigger-query").attr("id"));
var columns = [];
var fields = [];
var comboboxFields = [];
// Hide the graph search panel
$("#graphSearch").fadeOut(1400);
// Show the results and visualization button/tab
$("#nav-trigger-results").fadeIn(1400);
$("#nav-trigger-visualization").fadeIn(1400);
$.each(data.results.head.vars, function(index, value) {
columns.push({'field': value, 'title': value});
var to = {};
to[value] = {type: "string"};
fields.push(to);
// Let's also populate the two Comboboxes for the Visualization while we are at it
comboboxFields.push({'text': value, 'value': value});
});
// Now, set the two combobox datasources for visualizations
var categoriesDS = new kendo.data.DataSource({
data: comboboxFields
});
vizCategoryAxis.setDataSource(categoriesDS);
var valuesDS = new kendo.data.DataSource({
data: comboboxFields
});
vizValueAxis.setDataSource(valuesDS);
var dataBindings = [];
$.each(data.results.results.bindings, function(index1, value) {
var tempobj = {};
$.each(value, function(k1,v1) {
tempobj[k1] = v1.value;
});
tempobj.id=index1;
dataBindings.push(tempobj);
});
var configuration = {
dataSource: {
data: dataBindings,
pageSize: 25
},
height: 400,
scrollable: true,
sortable: true,
filterable: true,
reorderable: true,
resizable: true,
toolbar: ["excel"],
excel: {
allPages: true,
filterable: true,
proxyURL: "/saveExcel"
},
pageable: {
input: true,
numeric: false,
pageSizes: true
},
'columns': columns,
dataBound: function(e) {
$(e.sender.element).find('td').each(function() {
var temp = $(this).html();
if (isUrl(temp)) {
$(this).html('' + temp + '');
}
});
}
};
// Create the popup window
var gridWindow = $("#resultsPopup").kendoWindow({
width: "70%",
title: "Query Results",
actions: [
"Minimize",
"Maximize",
"Close"
]
}).data('kendoWindow');
// Center and show the popup window
gridWindow.center().open();
// Create/update/refresh the grid
resultsGrid.setOptions(configuration);
resultsGrid.dataSource.page(1);
$("#nav-trigger-results").on('click',function() {
// Center and show the popup window
gridWindow.center().open();
});
}).fail(function(xhr) {
// If we are timed-out
if (xhr.status === 401) {
// First, clear the host, database, and status text
$("#host_label").html('');
$("#DB_label").html('');
$("#status_label").html('');
// Next, disable the query button
$("#querySubmitButton").attr('disabled',true);
// Change "login" tab text color to red so we know we are no longer logged in
var styles = { 'color': "#FFCCD2" };
$("#nav-trigger-login").css(styles);
popup.show("Session for " + host + " has timed out, please log back in.","error");
}
else {
// Enable the query button
$("#querySubmitButton").removeAttr('disabled');
popup.show("Error, no results (" + xhr.status + " " + xhr.statusText + ")","error");
}
});
}
// Function to connect to the query queue websocket
function queueWebsocketConnect() {
var qws = new WebSocket('wss://endeavour:3000/queue');
// Let's disconnect our Websocket connections when we leave the app
$(window).on('unload', function() {
console.log('Websocket connection closed');
qws.close();
});
// Status websocket onopen
qws.onopen = function () {
console.log('Websocket connection opened');
popup.show("Websocket connection opened","success");
};
qws.onclose = function (event) {
console.log('Websocket connection closed');
popup.show("Websocket connection closed","info");
};
qws.onmessage = function (msg) {
var res = JSON.parse(msg.data);
var tableRows = '<thead><tr><td>Query Position</td><td>Query ID</td><td>Kill/Cancel Query</td></tr></thead><tbody>';
if (res.executing != null && res.entry.length > 0) {
$("#queryQueue").empty();
tableRows += '<tr><td>1</td><td>' + res.executing.id + '</td><td><input type="button" class="k-button" value="Kill"></td></tr>';
$.each(res.entry, function(index,object) {
tableRows += '<tr><td>' + (object.pos + 1) + '</td><td>' + object.query.id + '</td><td><input type="button" class="k-button" value="Cancel"></td></tr>';
});
tableRows += '</tbody>';
$("#queryQueue").html(tableRows);
}
else if (res.executing != null) {
$("#queryQueue").empty();
tableRows += '<tr><td>1</td><td>' + res.executing.id + '</td><td><input type="button" class="k-button" value="Kill"></td></tr>';
tableRows += '</tbody>';
$("#queryQueue").html(tableRows);
}
else {
console.log(res);
$("#queryQueue").empty();
}
};
}
// Function to connect to the stats websocket
function websocketConnect () {
// Set up websocket connection for system stats
var ws = new WebSocket('wss://endeavour:3000/stats');
// Let's disconnect our Websocket connections when we leave the app
$(window).on('unload', function() {
console.log('Websocket connection closed');
ws.close();
});
// Status websocket onopen
ws.onopen = function () {
console.log('Websocket connection opened');
popup.show("Websocket connection opened","success");
};
// Status websocket onclose
ws.onclose = function (event) {
// Disable the query button
$("#querySubmitButton").attr('disabled',true);
// Change "login" tab text color to red so we know we are no longer logged in
var styles = { 'color': "#FFCCD2" };
$("#nav-trigger-login").css(styles);
// Clear the host, database, and status text
$("#host_label").html('');
$("#DB_label").html('');
$("#status_label").html('');
console.log('Websocket connection closed');
popup.show("Websocket connection closed","error");
$("#websocketReconnectButtonYes").on('click', function() {
websocketConnect();
queueWebsocketConnect();
websocketReconnect.close();
});
$("#websocketReconnectButtonNo").on('click', function() {
websocketReconnect.close();
});
websocketReconnect.center().open();
};
// When updates are received, push them out to update the details
var logoutCount = 0;
ws.onmessage = function (msg) {
if (msg.data === 'loggedOut') {
// Ensure we only emit this one time instead of a stream of them
if (logoutCount == 0) {
// Disable the query button
$("#querySubmitButton").attr('disabled',true);
// Change "login" tab text color to red so we know we are no longer logged in
var styles = { 'color': "#FFCCD2" };
$("#nav-trigger-login").css(styles);
// Clear the host, database, and status text
$("#host_label").html('');
$("#DB_label").html('');
$("#status_label").html('');
console.log("Session for " + $("#host_label").html() + " has timed out, please log back in.");
popup.show("Session for " + $("#host_label").html() + " has timed out, please log back in.","error");
}
logoutCount = 1;
}
else {
logoutCount = 0;
var res = JSON.parse(msg.data);
var host = $("#host_label").html();
var pdatabase = $("#DB_label").html();
var pstatus = $("#status_label").html();
// Disable the query button unless the database is "CONNECTED"
if ($("#status_label").html() !== res.current.databaseStatus) {
if (res.current.databaseStatus !== "CONNECTED") {
$("#querySubmitButton").attr('disabled',true);
}
else {
$("#querySubmitButton").removeAttr('disabled');
}
if (res.current.databaseStatus == 'CONNECTED' || res.current.databaseStatus == 'STOPPED') {
$("#startDB").removeAttr('disabled');
}
else {
$("#startDB").attr('disabled',true);
}
}
// Maybe a more intelligent way to do this, but need to make sure that if the cookie is still valid, then populate the database login stuff
if ($("#dbConfigHost").val() == "" && $("#dbConfigUser").val() == "") {
$("#dbConfigHost").val(res.host);
$("#dbConfigUser").val(res.user);
// Change "login" tab text color to green so we know we are logged in
var styles = { 'color': "#C5E6CC" };
$("#nav-trigger-login").css(styles);
var databasesDS = new kendo.data.DataSource({
data: res.databases.database
});
databasePicker.setDataSource(databasesDS);
}
// Update the labels when values change
if (res.host != $("#host_label").html()) {
$("#host_label").html(res.host);
popup.show("Host changed to " + res.host,"info");
}
if (pdatabase != res.current.name) {
$("#DB_label").html(res.current.name);
popup.show("Database changed to " + res.current.name ,"info");
}
if (pstatus != res.current.databaseStatus) {
$("#status_label").html(res.current.databaseStatus);
}
// Update the sparklines
cpulog.options.series[0].data = res.system.cpu;
cpulog.refresh();
memlog.options.series[0].data = res.system.mem;
memlog.refresh();
}
};
// Open the websocket connection to listen for changes to the query list
var queryWS = new WebSocket('wss://endeavour:3000/queryList');
queryWS.onmessage = function(msg) {
var res = JSON.parse(msg.data);
var queriesDS = new kendo.data.DataSource({
data: res
});
cannedQuery.setDataSource(queriesDS);
};
}
Well, I guess when one has been heading down one road for a while, one assumes that it is in the right direction. After further head-scratching, I found the issue and it was related to the blocking/non-blocking nature of my backend web-framework. As it turns out, in Mojolicious (Perl web-framework), http calls can be either synchronous or asynchronous depending on how one writes the call.
my $tx = $ua->get('http://foo.bar?query=getSomeFoo');
if($tx->success) {
$self->render($tx->res->content);
}
else {
$self->rendered($tx->res->code);
}
This is a blocking/synchronous request. Nothing happens until after the GET finishes. On the other hand, if one writes the request like so, it is an asynchronous request:
$ua->get('http://foo.bar?query=getSomeFoo' => sub {
my ($ua,$tx) = #_;
if($tx->success) {
$self->render($tx->res->content);
}
else {
$self->rendered($tx->res->code);
}
});
So, if anyone else has encountered this issue...here is the answer. If I am the only idiot on the planet that has committed this blunder...then I guess I have put my shame out there for all to have a good chuckle at.
Bottom line was that this was well documented in the Mojolicious docs...but I had been doing it one way for so long that I completely forgot about it.
Cheers!
var dbShell;
function doLog(s){
/*
setTimeout(function(){
console.log(s);
}, 3000);
*/
}
function dbErrorHandler(err){
alert("DB Error: "+err.message + "\nCode="+err.code);
}
function phoneReady(){
doLog("phoneReady");
//First, open our db
dbShell = window.openDatabase("SimpleNotes", 2, "SimpleNotes", 1000000);
doLog("db was opened");
//run transaction to create initial tables
dbShell.transaction(setupTable,dbErrorHandler,getEntries);
doLog("ran setup");
}
//I just create our initial table - all one of em
function setupTable(tx){
doLog("before execute sql...");
tx.executeSql("CREATE TABLE IF NOT EXISTS notes(id INTEGER PRIMARY KEY,title,body,updated)");
doLog("after execute sql...");
}
//I handle getting entries from the db
function getEntries() {
//doLog("get entries");
dbShell.transaction(function(tx) {
tx.executeSql("select id, title, body, updated from notes order by updated desc",[],renderEntries,dbErrorHandler);
}, dbErrorHandler);
}
function renderEntries(tx,results){
doLog("render entries");
if (results.rows.length == 0) {
$("#mainContent").html("<p>You currently do not have any notes.</p>");
} else {
var s = "";
for(var i=0; i<results.rows.length; i++) {
s += "<li><a href='edit.html?id="+results.rows.item(i).id + "'>" + results.rows.item(i).title + "</a></li>";
}
$("#noteTitleList").html(s);
$("#noteTitleList").listview("refresh");
}
}
function saveNote(note, cb) {
//Sometimes you may want to jot down something quickly....
if(note.title == "") note.title = "[No Title]";
dbShell.transaction(function(tx) {
if(note.id == "") tx.executeSql("insert into notes(title,body,updated) values(?,?,?)",[note.title,note.body, new Date()]);
else tx.executeSql("update notes set title=?, body=?, updated=? where id=?",[note.title,note.body, new Date(), note.id]);
}, dbErrorHandler,cb);
}
function init(){
document.addEventListener("deviceready", phoneReady, false);
//handle form submission of a new/old note
$("#editNoteForm").live("submit",function(e) {
var data = {title:$("#noteTitle").val(),
body:$("#noteBody").val(),
id:$("#noteId").val()
};
saveNote(data,function() {
$.mobile.changePage("index.html",{reverse:true});
});
e.preventDefault();
});
//will run after initial show - handles regetting the list
$("#homePage").live("pageshow", function() {
getEntries();
});
//edit page logic needs to know to get old record (possible)
$("#editPage").live("pageshow", function() {
var loc = $(this).data("url");
if(loc.indexOf("?") >= 0) {
var qs = loc.substr(loc.indexOf("?")+1,loc.length);
var noteId = qs.split("=")[1];
//load the values
$("#editFormSubmitButton").attr("disabled","disabled");
dbShell.transaction(
function(tx) {
tx.executeSql("select id,title,body from notes where id=?",[noteId],function(tx,results) {
$("#noteId").val(results.rows.item(0).id);
$("#noteTitle").val(results.rows.item(0).title);
$("#noteBody").val(results.rows.item(0).body);
$("#editFormSubmitButton").removeAttr("disabled");
});
}, dbErrorHandler);
} else {
$("#editFormSubmitButton").removeAttr("disabled");
}
});
}
Dats my code, awfully long, huh?
Well anyways I got most of it from here, however I get an error on line 67 saying "TypeError: 'undefined' is not a function.".
I'm using Steroids (phonegap-like) and testing dis on an iPhone simulator. I'm sure it uses some cordova for the database work.
Thank you for your help :-)
Which jQuery version do you use? Because .live() was removed with jQuery 1.9 (http://api.jquery.com/live/). You should use .on() instead: http://api.jquery.com/on/
I've tried everything I can think of to get this "send" button to work, but I'm not very good at javascript :(
http://www.kimscakes.biz/contactme.php
Prehaps someone here can tell me where i'm going wrong?
Many thanks
Gem
You are binding the submit before the element exists, move the code after the form or put it inside $(document).ready:
jQuery(document).ready(function () {
jQuery("#submit").click(function () {
console.log("button clicked");
// declare these vars
var name = jQuery("#name");
var email = jQuery("#email");
var message = jQuery("#message");
var human = jQuery("#human");
var success = jQuery("#success");
var error = jQuery("#error");
// reset these vars
success.html("");
error.html("");
// ajax call to script.php
jQuery.getJSON("mailer.php", {
name: name.val(),
email: email.val(),
message: message.val(),
human: human.val()
}, function (html) {
// if html from script.php == 1, happy days
if (html == '1') {
jQuery("#contact").hide()
success.html("Thank You, your message has been sent.")
error.show()
}
else {
error.html(html)
}
});
});
});