I have an ajax post that looks like this:
$.ajax({
type: "post",
dataType: "html",
url: "/MyController/MyAction",
data: AddAntiForgeryToken({
SomeValue: "Abc"
}, "#FormIdFromWhereToCopyAntiForgeryTokenFrom"),
success: function (response) {
if (response === "True") {
//do something
} else {
//call the function to try again in 10 seconds.
}
},
error: function (e) {
//call the function to try again in 10 seconds.
}
});
Now in certain scenarios, it is possible that this function will return an error, these are very rare scenarios, but possible and I want to handle them. For the purpose of the question, I don't think it important to dive into them. In any case, on my server side I have setup a check when an error happens with that scenario. I capture it and then I return a response that would normally tell browser to refresh itself. But since this is an ajax call, it won't do it. Here is the code for that:
public class CustomExceptionHandler : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
var exception = filterContext.Exception;
if (exception != null)
{
var exceptionType = exception.GetType();
var someType= typeof(SomeExceptionType);
if (exceptionType.IsInstanceOfType(someType) || someType == exceptionType)
{
filterContext.ExceptionHandled = true;
filterContext.Result = new RedirectResult(filterContext.HttpContext.Request.RawUrl);
return;
}
}
}
}
As you can see above, the idea is to tell the page to refresh itself and the problems will be resolved after that. However, I'm not sure how to check in my javascript in the error section, that the server sent back a Redirect Result so I can tell the browser to refresh.
Would I be looking at the headers or something else? Could you post an example of how I can solve this?
You can simply set a timeout to refresh the page, like this:
else {
//call the function to try again in 10 seconds.
settimeout(function(){
location.reload();
}, 10000);
}
Or have I missunderstood the question?
Related
This question already has answers here:
How should I use servlets and Ajax?
(7 answers)
HTTP request parameters are not available by request.getAttribute()
(1 answer)
Closed 3 years ago.
I'm trying to send the username to the servlet through an ajax call to check its availability, but the servlet show a null pointer exception.
I've also tried with the XMLHttpRequest instead of $.ajax.
This is my Javascript file:
$(document).ready(function() {
$("#reg-form").submit(function() {
var res = true;
if (!testUser()) {
res = false;
$("#erruser").css("display", "block");
$("#username").addClass("errclass");
} else {
$("#erruser").css("display", "none");
$("#username").removeClass("errclass");
}
return res;
});
});
function testUser() {
var el = $("#username").val();
var b = false;
$.ajax({
type: "POST",
url: "CheckUserServlet",
data: { user: el },
dataType: "json",
success: function(bool) {
alert(bool);
if (bool == "si") b = true;
},
error: function() {
alert("errore");
}
});
return b;
}
This is my servlet doPost method:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username=request.getAttribute("user").toString();
System.out.println("username servlet= "+username);
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
if (!ud.doRetrieveByUser(username)) {
response.getWriter().write("si");
return;
}
response.getWriter().write("no");
return;
}
Thanks!
CLIENT SIDE
Your test user function will always return false regardless of if the server is operating correctly because $.ajax() is an async function. There are a few ways around this. In your case, without knowing much more about what you are building, I would suggest removing the return value from your test user function, and moving your logic into the success/failure areas in the ajax callback. This way, the ajax call just does it's thing and lets the success function modify your page however you want.
function testUser() {
var el = $("#username").val();
$.ajax({
type: "POST",
url: "CheckUserServlet",
data: { user: el },
dataType: "json",
success: function(bool) {
alert(bool);
// put logic here
if (bool === "si") {
$("#erruser").css("display", "block");
$("#username").addClass("errclass");
} else {
$("#erruser").css("display", "none");
$("#username").removeClass("errclass");
}
},
error: function() {
alert("errore");
}
});
}
I would also suggest setting up the initial state of your page so that while this request is happening the user is shown something that makes sense. Answer the following question: "what do I show my users when the page does not know yet if it is a test user" and then set the initial state of the page accordingly
SERVER SIDE
I've always found interacting with java & JSON data a bit clunky, and your issue seems like something I've grappled with in the past.
Your question is "why is ajax sending null to the server". It may seem like that but what is really happening is that your server doesn't understand how to interpret the data it is getting. Take a look at this question about getting a JSON payload.. You need to tell your server how to parse the data coming from the client. If you were to inspect the data being sent, I would expect it looks something like this {"user":"blablabla"}.
If you have a class definition already, use that. For this I am using something that looks like this:
public class UserRequest {
String user;
}
// get the body as a string. Requires https://commons.apache.org/proper/commons-io/
String body = IOUtils.toString(request.getReader())
// parse the json with gson. Requires https://github.com/google/gson
Gson g = new Gson();
User u = g.fromJson(body, UserRequest.class);
String username = u.user;
I'm having a problem with something that is likely a simple error.
As you will notice below, I have a check for duplicate function that references external PHP checking a database. The PHP is working, and returning data.
When I use duplicationCheck.done() and parse the data, my if statement responds correctly (i.e., if the user has entered a duplicate, this checks that. HERE'S the issue: Despite my if statement below functioning correctly, when isDuplicate is set to true, it appears as undefined when the console.log command is called below the done() function. I can't figure out why. With my research, I think that it is a problem with the async nature of the AJAX call?
Thank you for your time. Any ideas?
$("#username_submit").click(function() {
function checkForDuplication(username) {
return $.ajax({
url: 'static/experiments/computerized_handwriting/random_assignment.php',
type: 'POST',
data: {userName: username}
});
}
var duplicationCheck = checkForDuplication($('input:text').val());
var isDuplicate;
duplicationCheck.done(function(data){
var response = JSON.parse(data);
if(response.data['json_array'] == "duplicate"){
isDuplicate = true;
alert("dup");
} else {
isDuplicate = false;
}
});
console.log(isDuplicate);
....
This is due to the asynchronous nature of ajax.
You need to check for the duplication once it returns from the server in the done function.
But your duplicationCheck variable is not a reference to the function, but what it is returning.
The proper way would be like this:
$("#username_submit").click(function() {
$.ajax({
url: 'static/experiments/computerized_handwriting/random_assignment.php',
type: 'POST',
data: { userName: $('input:text').val()}
}).done(function() {
var response = JSON.parse(data);
if (response.data['json_array'] == "duplicate") {
isDuplicate = true;
alert("dup");
}
else {
isDuplicate = false;
}
console.log(isDuplicate);
});//done
});//submit click
....
Updated Question with Code
I have a situation where I am calling two nested ajax calls one after another. The first ajax call submits a form without the attachment. The result of the first ajax call will create a requestId and using second ajax call I have to attach multiple attachments to the created requestId.
The result of below code, both first and second ajax calls are being called N times of attachment. For ex:- If there are 3 attachments, createRequestId ajax call(first ajax call) called 3 times which creates 3 requestIds. My issue is, createRequestId ajax call needs to be called only one time (first time) and during rest of the loop, only the second ajax call should be called. How can I achieve this in the below code?
Current situation
RequestId 1,Attachment 1
RequestId 2,Attachment 2
RequestId 3, Attachment 3
Expected output
RequestId 1, Attachment 1, Attachment 2, Attachment 3
//loop through number of attachments in the form
$("#myDiv").find("input[type=file]").each(function(index,obj) {
var fObj = $(obj),
fName = fObj.attr("name"),
fileDetail = document.getElementById(fName).files[0];
//FileSize Validation
if(fileDetail !=undefined && fileDetail !=null)
{
if(fileDetail.size > 5*Math.pow(1024,2))
{
alert("Please upload the attachment which is less than 5 MB");
return false
}
}
$.ajax({ //First Ajax Call
url: 'http://..../createRequestId'
type:'POST'
data: stringify(formData)
success: function(resObj){
$("#showResponseArea span").removeClass("hide");
$("#showResponseArea span").removeClass("alert-success");
var requestId = resObj.requestId;
if(requestId>1 && fileDetail !=undefined && fileDetail !=null) {
$.ajax({ //Second Ajax Call
url: 'http://..../doAttach?fileName=' + fileDetail.name +
'&requestId=' +requestId,
type:'POST',
data: fileDetail,
success: function(resObj){
alert("Attachment Successful");
}
error : function(data) {
alert("Failed with the attachment");
}
});
}
},
error: funciton(resObj) {
alert("Some Error Occured");
}
});
});
I know this doesn't really answer your question in full, but if you don't mind me offering a little constructive code review. It's hard to really manage and debug code when it's all thrown into one big function with many lines, especially if you're nesting async calls (you're getting close to nested callback hell). There's a reason code like this can get hard to maintain and confusing.
Lets incorporate some Clean Code concepts which is to break these out into smaller named functions for readability, testability, and maintainability (and able to debug better):
First you don't need all those !== and undefined checks. Just do:
if (fileDetail)
and
if(requestId>1 && fileDetail)
that checks for both null and undefined on fileDetail.
Then I’d start to break out those two ajax calls into several named functions and let the function names and their signatures imply what they actually do, then you can remove unnecessary comments in code as well as once you break them out, typically you can find repeated code that can be removed (such as redundant post() code), and you will find that code you extracted out can be tested now.
I tend to look for behavior in my code that I can try to extract out first. So each one of those if statements could easily be extracted out to their own named function because any if statement in code usually translates to "behavior". And as you know, behavior can be isolated into their own modules, methods, classes, whatever...
so for example that first if statement you had could be extracted to its own function. Notice I got rid of an extra if statement here too:
function validateFileSize(fileDetail)
if(!fileDetail && !fileDetail.size > 5*Math.pow(1024,2)){
alert("Please upload the attachment which is less than 5 MB");
return false
};
};
So here's how you could possibly start to break things out a little cleaner (this could probably be improved even more but here is at least a start):
$("#myDiv").find("input[type=file]").each(function(index,obj) {
var fObj = $(obj),
fileName = fObj.attr("name"),
file = document.getElementById(fileName).files[0];
validateFileSize(file);
post(file, 'http://..../createRequestId');
});
// guess what, if I wanted, I could slap on a test for this behavior now that it's been extracted out to it's own function
function validateFileSize(file){
if(!file && !file.size > 5*Math.pow(1024,2)){
alert("Please upload the attachment which is less than 5 MB");
return false
};
};
function post(url, data){
$.ajax({
url: url,
type:'POST',
data: stringify(data),
success: function(res){
showSuccess();
var id = res.requestId;
if(id > 1 && file){
var url = 'http://..../doAttach?fileName=' + file.name + '&requestId=' + id;
postData(file, url);
}
},
error: function(err) {
alert("Some Error Occurred: " + err);
}
});
// I didn't finish this, and am repeating some stuff here so you could really refactor and create just one post() method and rid some of this duplication
function postData(file, url){
$.ajax({
url: url,
type:'POST',
data: file,
success: function(res){
alert("Attachment Successful");
},
error : function(data) {
alert("Failed with the attachment");
}
});
};
// this is behavior specific to your form, break stuff like this out into their own functions...
function showSuccess() {
$("#showResponseArea span").removeClass("hide");
$("#showResponseArea span").removeClass("alert-success");
};
I'll leave it here, next you could get rid of some of the duplicate $ajax() code and create a generic post() util method that could be reused and move any other behavior out of those methods and into their own so that you can re-use some of the jQuery ajax call syntax.
Then eventually try to incorporate promises or promises + generators chain those async calls which might make it a little easier to maintain and debug. :).
I think your loop is simply in the wrong place. As it is, you're iterating files and making both AJAX calls once.
Edit: I now show the appropriate place to do extra validations before the first AJAX call. The actual validation was not part of the question and is not included, but you can refer to JavaScript file upload size validation.
var fileSizesValid = true;
$("#myDiv").find("input[type=file]").each(function(index, obj) {
// First loop checks file size, and if any file is > 5MB, set fileSizesValid to false
});
if (fileSizesValid) {
$.ajax({ //First Ajax Call
url: 'http://..../createRequestId',
type: 'POST',
data: stringify(formData),
success: function(resObj) {
var fObj = $(obj),
fName = fObj.attr("name"),
fileDetail = document.getElementById(fName).files[0];
//loop through number of attachments in the form
$("#myDiv").find("input[type=file]").each(function(index, obj) {
$("#showResponseArea span").removeClass("hide");
$("#showResponseArea span").removeClass("alert-success");
var requestId = resObj.requestId;
if (requestId > 1 && fileDetail != undefined && fileDetail != null) {
$.ajax({ //Second Ajax Call
url: 'http://..../doAttach?fileName=' + fileDetail.name +
'&requestId=' + requestId,
type: 'POST',
data: fileDetail,
success: function(resObj) {
alert("Attachment Successful");
},
error: function(data) {
alert("Failed with the attachment");
}
});
}
})
},
error: function(resObj) {
alert("Some Error Occured");
}
});
}
As a side note, take care where you place your braces. In JavaScript your braces should always be at the end of the line, not the start. This is not a style preference thing as it is most languages, but an actual requirement thanks to semicolon insertion.
Try following code (Just a re-arrangement of your code and nothing new):
//loop through number of attachments in the form
var requestId;
$("#myDiv").find("input[type=file]").each(function(index,obj) {
var fObj = $(obj),
fName = fObj.attr("name"),
fileDetail = document.getElementById(fName).files[0];
//FileSize Validation
if(fileDetail !=undefined && fileDetail !=null)
{
if(fileDetail.size > 5*Math.pow(1024,2))
{
alert("Please upload the attachment which is less than 5 MB");
return false
} else if(!requestId || requestId <= 1){
$.ajax({ //First Ajax Call
url: 'http://..../createRequestId'
type:'POST'
data: stringify(formData)
success: function(resObj){
$("#showResponseArea span").removeClass("hide");
$("#showResponseArea span").removeClass("alert-success");
requestId = resObj.requestId;
secondAjaxCall(fileDetail);
},
error: funciton(resObj) {
alert("Some Error Occured");
}
});
} else if(requestId>1) {
secondAjaxCall(fileDetail);
}
}
});
function secondAjaxCall(fileDetail) {
$.ajax({ //Second Ajax Call
url: 'http://..../doAttach?fileName=' + fileDetail.name +
'&requestId=' +requestId,
type:'POST',
data: fileDetail,
success: function(resObj){
alert("Attachment Successful");
}
error : function(data) {
alert("Failed with the attachment");
}
});
}
I have this problem when I use setInterval and ajax for retrieving data from the database and if the data that I retrieve from the database is equal to saveHere then it will loop again until it does not match the variable saveHere, it freeze the browser until the data that I retrieve is not equal to saveHere.
Here is an example:
var saveHere = 'RED';
var interval = setInterval(function() {
var sample = $.ajax({
type: 'GET',
url: 'database.php',
data : data
}).responseText;
if (sample != 'RED') {
clearInterval(interval);
saveHere = sample;
}
else {
console.log('load again');
}
},1000);
I really need advice. Thank you in advance. Sorry for the grammar.
$.ajax is asynchronous and requires you to use a callback to get the response text.
Take a look at the documentation at http://api.jquery.com/jQuery.ajax/
What you want to do is to add a success parameter. Something like this:
var saveHere = 'RED';
doAjax();
function doAjax() {
$.ajax({
type: 'GET',
url: 'database.php',
data: data,
success: function (sample) {
if (sample != 'RED') {
saveHere = sample;
} else {
console.log('load again');
doAjax();
}
}
});
}
Notice how I've removed setInterval and instead wrapped the Ajax code in a function. The success callback will be called when the Ajax query has successfully finished, and give you the response. Once we have evaluated the response, we can run the doAjax function again to run the query again.
Without knowing the exact scenario, or what you're looking to achieve, I'd say the way you're going about your AJAX calls is very dangerous as it has the potential to constantly make a request every second, regardless of whether the server has had a chance to respond yet.
I'd be tempted to only make one request at a time, something like:
var saveHere = 'RED';
makeAjaxCall();
function makeAjaxCall() {
var url = 'database.php';
var data = {};
$.get(url, data, function(response_text){
if (response_text != 'RED')
{
saveHere = response_text;
// do whatever else you need...
}
else
{
// make another call...
console.log('calling again...');
makeAjaxCall();
}
}, "text");
}
You are clearing interval that means no interval will occur after that.
Instead what you can do is wrap interval inner code inside if condition as below.
var interval = setInterval(function()
{
if(sample != 'RED') {
var sample = $.ajax({
type: 'GET',
url: 'database.php',
data : data
}).responseText;
saveHere = sample;
}
else
{
console.log('load again');
}
},1000);
In your code you test for not equal to 'RED'.
if(sample != 'RED'){ . . .
That part of the loops stops the interval
If it doesn't equal red
}else{
It simple logs 'load again' without clearing the interval
What exactly are you trying to achieve ?
All I need is a method that returns true if the Url is responding. Unfortunately, I'm new to jQuery and it's making my attempts at writing that method rather frustrating.
I've seen several examples of jQuery using .ajax, but the code is consistently failing on me. What's wrong?
var urlExists = function(url){
//When I call the function, code is still executing here.
$.ajax({
type: 'HEAD',
url: url,
success: function() {
return true;
},
error: function() {
return false;
}
});
//But not here...
}
That isn't how AJAX works. AJAX is fundamentally asynchronous (that's actually what the first 'A' stands for), which means rather than you call a function and it returns a value, instead you call a function and pass in a callback, and that callback will be called with the value.
(See http://en.wikipedia.org/wiki/Continuation_passing_style.)
What do you want to do after you know whether the URL is responding or not? If you intended to use this method like this:
//do stuff
var exists = urlExists(url);
//do more stuff based on the boolean value of exists
Then what you instead have to do is:
//do stuff
urlExists(url, function(exists){
//do more stuff based on the boolean value of exists
});
where urlExists() is:
function urlExists(url, callback){
$.ajax({
type: 'HEAD',
url: url,
success: function(){
callback(true);
},
error: function() {
callback(false);
}
});
}
urlExists() can not return because it needs wait for the request.
Either pass it a callback, or make it synchronous (not recommended, because it locks the browser).
var urlExists = function(url, callback) {
if ( ! $.isFunction(callback)) {
throw Error('Not a valid callback');
}
$.ajax({
type: 'HEAD',
url: url,
success: $.proxy(callback, this, true),
error: $.proxy(callback, this, false)
});
};
Then you can do
urlExists('/something', function(success) {
if (success) {
alert('Yay!');
} else {
alert('Oh no!');
}
});
It also worth mentioning the same origin policy.
Also, returning from an anonymous function's scope will not return in the parent function (like in your original example). It just returns that inner function. To return from an inner to a parent, set a flag and return it.
Basically, there is nothing wrong with your code. See it work here:
http://jsfiddle.net/PK76X/
My guess is that you're using it to check the availability of content on a different domain, which fails because browsers don't allow cross domain ajax-requests.
If the url is from the same domain as your page you can do it. But if it is from a different domain, for example google.com, then it will fail due to cross domain security.
In general, you should probably run your script in Firefox using the firebug plugin. It will give you the details needed to solve the issue.
The ajax and post methods are asynchronous, so you should handle the result in a callback method.
AJAX is basically asynchronous, and that's why the behavior you are describing.
I've used the following, which is free of cross origin, to get a simple true/false indication whether a URL is valid, in a synchronous manner:
function isValidURL(url) {
var encodedURL = encodeURIComponent(url);
var isValid = false;
$.ajax({
url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + encodedURL + "%22&format=json",
type: "get",
async: false,
dataType: "json",
success: function(data) {
isValid = data.query.results != null;
},
error: function(){
isValid = false;
}
});
return isValid;
}
The usage is then trivial:
var isValid = isValidURL("http://www.wix.com");
alert(isValid ? "Valid URL!!!" : "Damn...");
Hope this helps