Asynchronous AJAX call completes after function call. Solve WITHOUT JQUERY - javascript

I need an AJAX API call to complete before it's containing function does. All the solutions I have looked up use jQuery, which I do not want to add as a dependency just to make a single REST call...
I have been reading the following question How do I return the response from an asynchronous call? and am still attempting to make it work. Again, I do not want to add jQuery as a dependency.
Right now if a failing zip code value is entered, when the user clicks Submit an alert will show the other failing business rules without the "Mismatch in State and Zip." error. When logging to console I see that the REST call is made and a successful response received, but it appears alert(error) is called before the async REST call has completed and appended the value of error.
JS
function checkForm(form){
var state = form.state;
var zip = form.zip;
var error = '';
var flag = 0;
var ckZip = checkZip(state, zip);
if (ckZip.flag == 1){
flag = 1;
}
error += ckZip.error;
// show error and disable form submit if flag == 1
if (flag == 1){
alert(error);
return false;
}
}
function checkZip(state, zip){
var state = form.state;
var zip = form.zip;
var error = '';
var flag = 0;
// check if value entered
if (zip == ''){
error += "Please provide a zip/postal code.\r\n";
flag = 1;
}
// business rule: cannot enter - in a ZIP
if (zip.search(/\x2d/) != -1){
error += "Please remove dash from zip or postal code.\r\n";
flag = 1;
}
// check if state and zip match
// IMPORTANT: Fill in your client key
var clientKey = "this-is-a-valid-key";
var zipcode = zip.substring(0, 5);
var url = "https://www.zipcodeapi.com/rest/"+clientKey+"/info.json/" + zipcode + "/radians";
// Make AJAX request
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.onreadystatechange = function() {
if (this.readyState === 4) {
if (this.status >= 200 && this.status < 400) {alert("Got it");
// Success!
var data = JSON.parse(this.responseText);alert(data.state);
if (data.state != state){
error += "Mismatch in State and Zip.\r\n";
flag = 1;
}
} else {
// Error :(
var response = JSON.parse(this.responseText);
error += "error: " + response.error_msg;
}
}
};
request.send();
request = null;
return {flag: flag, error: error};
}
HTML
<form>
<select id="state" name="state">
<option value="" selected=""></option>
<option value="AA">APO AA</option>
<option value="AE">APO AE</option>
<option value="AP">APO AP</option>
<option value="AL">Alabama</option>
<option value="AK">Alaska</option>
<option value="AZ">Arizona</option>
<option value="AR">Arkansas</option>
<option value="CA">California</option>
<option value="CO">Colorado</option>
<option value="CT">Connecticut</option>
<!-- ... -->
</select>
<input type="text" id="zip" name="zip" value="">
<input type="Submit" id="Submit" name="Submit" value="Continue" onclick="return checkForm(this.form)">
</form>

The only way to make your function actually return the information from the ajax call is to make the ajax call synchronous. I strongly recommend that you don't do that. It locks up the UI of the browser tab (at least) during the call, making for a poor user experience, and moreover there's no need.
Instead, embrace the asynchronous call and learn how to deal with the fact that the function cannot return the information as a return value; see this question and its answers for how to do that. It's really not as difficult as people sometimes think. :-)
Here's how you can make your checkZip work asynchronously:
First, move the call from the submit button to the form itself:
<form onsubmit="return checkZip(this)">
Now, make checkZip always prevent form submission by returning false and have it submit the form when the ajax is done:
function checkZip(form) {
// ...
request.onreadystatechange = function() {
// ...
if (/* it's okay to submit the form*/) {
form.submit(); // Does NOT call the handler again
} else {
// show error to user
}
};
// Stop the initial form submission
return false;
}
Note: The form will not contain the Submit field with the value Continue, since when it was really submitted, that button wasn't pressed. If you need it to, remove the name from the submit button and instead include a hidden field:
<input type="hidden" name="Submit" value="Continue">
But just for completeness, it is possible to make the ajax call synchronous: The third argument to open is a flag where true = asynchronous and false = synchronous, so:
request.open('GET', url, false);
// ----------------------^^^^^
But again, I strongly recommend that you don't do that.

You could either make your XMLHTTPRequest synchronous:
var request = new XMLHttpRequest();
request.open('GET', url, false);
Although as others have pointed out this is not recommended.
Another option would be to wrap your alert in a timeout that defers execution for some small amount of time, enough to give your request time to process:
setTimeout(function() {
// show error and disable form submit if flag == 1
if (flag == 1){
alert(error);
return false;
}
}, 1000);

Related

ReferenceError Cannot find variable createXMLHTTPRequestObject

I have a simple input box with a submit button which, when clicked, makes an XHR request to a server-side PHP for some information. In its simplest form, the markup looks like this:
<input type="text" id="word" class="form-control input-lg lookup-field" placeholder="Enter a Spanish or English word" oninput="deleteicon();" required>
<button class="btn btn-lg btn-brown lookup-submit" type="submit" id="lookup">Lookup</button>
The button's onclick event triggers a function that performs the XHR request:
$('#lookup').click(function(){ testlookup($('#word').val()); return(false); });
The testlookup() function is as below:
function testlookup(lookupword){
var mean = document.getElementById('meaning');
var waittext = '<div id="loading text-center"><i class="fa fa-4x fa-spinner fa-spin"></i></div>';
var hr = createXMLHTTPRequestObject();
var url = '/assets/engines/dictengine.php';
var vars = "lookup_word=" + lookupword;
document.getElementById('word').value = lookupword;
hr.open("POST", url, true);
hr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
hr.onreadystatechange = function(){
if(hr.readyState == 4 && hr.status == 200){
var return_data = hr.responseText;
mean.innerHTML = return_data;
else if(hr.status == 500){ mean.innerHTML = "Something went wrong! Please try again later..."; }
}
hr.send(vars);
mean.innerHTML = waittext;
}
I fail to see why this should ever refuse to work and would really appreciate some help seeing the issue. Every time I enter a value in the input box and click the button, the console briefly flashes a "Can't find variable createXMLHTTPRequestObject" error before the browser proceeds to refresh the page with a "?" appended to the URL. What could be the issue here and also why is the "?" getting appended to the URL if I have duly terminated my onclick function with a return(false) statement?
The code is implemented at peppyburro.com/test-dictionary.
You are trying to call a function named createXMLHTTPRequestObject, but it doesn't exist. The JS throws an exception and never reaches the return (false) statement.

JSP Chat - How I can parse the value from HTML to JSP page?

I have to make a chat with JSP, AJAX and Java and I have a problem: when I try to use my variable to store value of a input text, this variable is null.
If I add 'action' property to the form, the variable 'textParam' will have the value of the input text, but, if I do that I have to redirect with action to a page and I don't what that.
I need to process something bigger in the JSP page and then to reload in the HTML page (which is a JSP page) (the reload part is not on actual probem).
How I can make to populate 'textParam' with the input text value when I press the button?
PS: I need to make it with pure javascript, not with some libraries :)
The JSP which have to process is:
String textParam = request.getParameter("chatMessage");
System.out.println("textParam = " + textParam);
My form it look like that:
<form id="frmmain" name="frmmain" onsubmit="return blockSubmit();">
<input type="text" id="chatMessage" name="chatMessage" style="width: 447px;" />
<input type="button" name="btn_send_chat" id="btn_send_chat" value="Send" onclick="sendChatText();" />
</form>
The .js file it's this:
var request = getXmlHttpRequestObject();
var response = getXmlHttpRequestObject();
var lastMessage = 0;
var mTimer;
function getXmlHttpRequestObject() {
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
} else if(window.ActiveXObject) {
return new ActiveXObject("Microsoft.XMLHTTP");
}
}
function sendChatText() {
if(document.getElementById('chatMessage').value == '') {
alert("You have not entered a message");
return;
}
if (request.readyState == 4 || request.readyState == 0) {
request.open("POST", 'getChat2.jsp?chat=1&last=' + lastMessage, true);
request.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
request.onreadystatechange = handleSendChat;
var param = 'message=' + document.getElementById('chatMessage').value;
param += '&chat=1';
request.send(param);
document.getElementById('chatMessage').value = '';
}
}
function handleSendChat() {
clearInterval(mTimer);
getChatText();
}
function blockSubmit() {
sendChatText();
return false;
}
The problem is here:
String textParam = request.getParameter("chatMessage");
I was trying to get 'chatMessage' parameter, which it was only the name of the input. The solve is to get 'message' param which it was defined and requested in js:
String textParam = request.getParameter("message");

Redirect page after Submitting Form

I have a form, which can either be submitted via AJAX or usual way, working with the submit button. The Ajax part is here:
parentForm.onsubmit = function(e) { // e represents trigering event
if(srteValidateMode()){ // works only in WYSIWYG mode
var outputString = srteEditArea.innerHTML; // first we prepare the text output data
outputString = outputString
.replace(/<(\/?)strong>/gi, '<$1b>') // unify output tags for all browsers -> B I P (instead of strong em div)
.replace(/<(\/?)em>/gi, '<$1i>')
.replace(/<(\/?)br>/gi, '<p>')
.replace(/<(\/?)div/gi, '<$1p');
document.getElementById('simpleRTEoutput').value=outputString; // pass output string to hidden form field
if (srteAjaxSubmit) { // ajax version - filling FormData
e.preventDefault(); // canceling the submit function - we will call it with Ajax
var srteFormData = new FormData(e.target); // getting form data from submitted form
var ajaxRequest = new XMLHttpRequest(); // now going to invoke AJAX
ajaxRequest.onreadystatechange = function () {
if (ajaxRequest.readyState == 4 && ajaxRequest.status == 200) {
srteShowInfo(ajaxRequest.responseText); // return message and display as info window
}
}
ajaxRequest.open("POST", e.target.action); // getting target script from form action
ajaxRequest.send(srteFormData); // send FormData
}
else { // Standard submit
return true; // true = standard submit will proceed (works ok)
}
}
else {return false;} // on false return form will not be submitted
};
It works fine. Now I want to add redirection functionality - clicking on another (non submit) button with some onclick function to SAVE (do the predefined submit) AND redirect. I have such Idea (not tested), but not sure it this might work especially in the AJAX part.
function srteSubmitForm(redirectTo) {
if (srteAjaxSubmit) { // redirect when submitted via Ajax Call
parentForm.submit(); // save form data
window.location.href = redirectTo; // change location - does it wait for previous function ?
}
else {
parentForm.action = parentForm.action + '?redirect=' + redirectTo; // rest handled by target PHP
parentForm.submit();
}
}
Button in HTML then would look like:
<input type="button" onclick="srteSubmitForm(\"somepage.php?page=A\")" value="Redirect A">
<input type="button" onclick="srteSubmitForm(\"somepage.php?page=B\")" value="Redirect B">
<input type="button" onclick="srteSubmitForm(\"somepage.php?page=C\")" value="Redirect C">
I am not sure, if I need to wait for the AJAX to be finished somehow before redirect ? Or any other way how redirect after the submit?
no jQuery solutions, please.
Thanks, Jan
Why not add a 'callback' parameter to your submit method that gets called when the call completes.
parentForm.submit(function(status){
//The call completed, you can display a confirm message 'Form submitted,
//now redirecting' (because it's not nice to redirect without warning ;)
window.location.href = redirectTo;
});
And in your submit:
ajaxRequest.onreadystatechange = function () {
if (ajaxRequest.readyState == 4 && ajaxRequest.status == 200) {
srteShowInfo(ajaxRequest.responseText);
if(callback instanceof Function) callback(ajaxRequest.responseText);
}
}

Sending HTML Form Multiple <select> box via POST request with AJAX?

I have an html form with a multiple select box. I can't figure out how to send the values to my php application with AJAX via a post request. It works just fine if I use a GET request and use a single select box but not when I use a multiple select box. The idea is for users to hold control (or command with mac) and select one or more categories. Depending on which categories are selected will determine what other form options will be displayed using AJAX. The select box looks like this:
Edit: SOLVED
<select multiple name="categories[]" onclick="sendCategories(this)">
<option value="0">Category 1</option>
<option value="1">Category 2</option>
<option value="2">Category 3</option>
</select>
My javascript function looks like this:
function sendCategories(sel){
if (window.XMLHttpRequest)
{
xmlhttp=new XMLHttpRequest();
}
else
{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("my_div").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("POST","http://www.mysite.com/update_categories.php",true);
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
var values = $(sel).serialize();
xmlhttp.send(values);
}
You'll have to generate the query string to send in the POST on your own. Here's the HTML tag to use:
<select multiple name="categories[]" onchange="sendCategories(this);">
And the Javascript function:
function sendCategories(sel){
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
document.getElementById("my_div").innerHTML = xmlhttp.responseText;
}
};
xmlhttp.open("POST","http://www.mysite.com/update_categories.php",true);
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var values = [], i, j, cur;
for (i = 0, j = sel.options.length; i < j; i++) {
cur = sel.options[i];
if (cur.selected) {
values.push(encodeURIComponent(cur.value));
}
}
if (values.length) {
values = encodeURIComponent(sel.name) + "=" + values.join("&" + encodeURIComponent(sel.name) + "=");
} else {
values = null;
}
xmlhttp.send(values);
}
Note that I changed the event from onclick to onchange, but that's really up to you whether you want this function to run when the element is clicked, or its value is truly changed...it can reduce some unnecessary calls.
This should generate a querystring that is normally used for sending values for a <select> with multiple options selected.
Here's a jsFiddle that demonstrates how the querystring is being generated here: http://jsfiddle.net/kKWQM/
You can do something like this,
<select multiple name="categories[]" onclick="sendCategories(this)">
And Make AJAX using JQuery,
function sendCategories(sel){
var values = $(select).serialize();
console.log (values); // See if you get the serialized data in console.
$.ajax({
type: 'POST',
url: "http://www.mysite.com/update_categories.php"
data: values,
success: function (data) {
document.getElementById("my_div").innerHTML = data;
}
});
}
And FYI, Netscape event binding model is deprecated, you could use the cross browser event binding like this
You can implement the solution however you would like using JS string and array functions. Effectively, the string you need to send to Apache should contain a pattern like:
xxx[]=a&xxx[]=b&xxx[]=c
where the SELECT element's name is xxx[] in your form and a, b, and c are three values the user selected.
So yes, you are repeating a key name as many times as the user selected a different option in the SELECT.
In JS you can use an array of selected options:
selected_options.join("&xxx[]=") to produce that pattern.
jQuery should make this easier for you. Calling .val() on a wrapped select returns an array of the selected values. You just have to post these to the server:
HTML:
<html>
<body>
<form>
<select name="mySelect" multiple="on">
<option value="1">Uno</option>
<option value="2">Dos</option>
<option value="3">Tres</option>
</select>
</form>
<input id="submitButton" type="button" value="Click To Submit"/>
</body>
</html>
JavaScript:
$(function() {
$('#submitButton').click(function() {
var valuesArray = $('select[name=mySelect]').val()
$.ajax({
type: 'POST',
url: '/path/to/php', // your php url would go here
data: { mySelect: valuesArray }
}).done(function(msg) {
// parse response from msg
});
});
});

Javascript code for handling Form behaviour

Here's how the situation looks :
I have a couple simple forms
<form action='settings.php' method='post'>
<input type='hidden' name='setting' value='value1'>
<input type='submit' value='Value1'>
</form>
Other small forms close to it have value2, value3, ... for the specific setting1, etc.
Now, I have all these forms placed on the settings.php subpage, but I'd also like to have copies of one or two of them on the index.php subpage (for ease of access, as they are in certain situations rather frequently used).
Thing is I do not want those forms based on the index.php to redirect me in any way to settings.php, just post the hidden value to alter settings and that's all.
How can I do this with JS ?
Cheers
Yes, you could use an ajax call to send a request to the settings.php file. You'd probably want that PHP code to return something that the JavaScript can use to know if the request was successful or not (for example, using JSON instead of HTML).
Here is an ajax getData function.
function getData(dataSource, targetDiv){
var XMLHttpRequestObject = false;
if (window.XMLHttpRequest) {
XMLHttpRequestObject = new XMLHttpRequest();
} else if (window.ActiveXObject) {
XMLHttpRequestObject = new
ActiveXObject("Microsoft.XMLHTTP");
}
if(XMLHttpRequestObject) {
var obj = document.getElementById(targetDiv);
XMLHttpRequestObject.open("GET", "settings.php?form="+dataSource+"&t="+new Date().getTime());
XMLHttpRequestObject.onreadystatechange = function()
{
if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) {
obj.innerHTML = XMLHttpRequestObject.responseText;
}
}
XMLHttpRequestObject.send(null);
}
}
use this function to send the form to your setting.php file which should return confirmation message to index.php(inside targetDiv).
Parameters of the function
1) dataSource - is the variable value that you send to settings.php
2) targetDiv - is the div on index php that with display the response from settings.php
Hope it makes sense.

Categories