How to receive messages from backend asynchronously? - javascript

I need to verify usernames, so when user enters the username it should be sent to backend to verify its availability. I have the following code but have doubt in receiving the available or unavailable message from backend.
function verifyUsername(value){
if(window.XMLHttpRequest)
{
xmlhttp = new XMLHttpRequest();
}
else
{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
document.getElementById("mymessage").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("get","verifyUsername?username="+value,false);
xmlhttp.send();
}
....
<div id="mymessage"></div>
....
Server End Psuedo Code (actual implementation: Java)
....
if(verify(username))
return "Username is not available";
else
return "username is available";

I'll give a jQuery example of this, I won't bother with the pure JavaScript version. What you are looking for is a callback function to fire once the ajax request has been returned.
// listen to a click event on a button OR something
$("#buttonName").on("click", function(event){
// prevent any default activity
event.preventDefault();
// get your value
var value = $("#mymessage").val();
// jQuery ajax event
$.ajax({
url : "verifyUsername?username="+value,
type: 'GET'
}).done(function ( data ) {
if ( console && console.log ) {
console.log( "Data returned :"+data )
// do something else
}
}):
.done() is the success callback option, there are others as well:
// jQuery ajax event
$.ajax({
url : "verifyUsername?username="+value,
type: 'GET'
})
// successful callback
.done(function(){ // success })
// fail/error callback
.fail(function(){ // fail })
// completed callback
.always(function(){ // will always execute, even if request fails })
});
Reference : http://api.jquery.com/jQuery.ajax/

If I am understanding the problem correctly, it is, "returning the correct response back from the server-side".
The actual implementation is mentioned as Java, so I am assuming there is a backend Servlet that the Ajax request submits to.
You would need to get a handle on the HttpServletResponse object in your doGet method(as you are using get), add your logic to verify the username and the send the response text back.
Something like
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException
{
String username = request.getParameter(username);
String responseText = "";
boolean isUserAval;
//add your logic to verify username setting isUserAval to true/false accordingly
response.setContentType("text/html");
PrintWriter out = response.getWriter();
if(isUserAval)
{
responseText = "Username is available";
}
else
{
responseText = "Username is not available";
}
out.println(responseText);
out.close();
}

Use this function below... You'll also notice, request will have a readystate and stuff like that, your looking for prolly statusCode between 200-202, and ready state of 4, and a statusText of OK
var request = $.get(url, function(event){
//If your within your application your url can be the method you need
//I.E. Ruby URL post would be /api/v1/users/find_user_by_ID
//This URL Points to the api/v1 folder than the users controller
//Than finally the method inside the controller (find_user_by_ID)
}
I also believe that whatever your doing, doesn't need to be in javascript, if your using PHP or Ruby, you can simply add php or ruby tags and create if statements, than use javascript to add and remove classes, or toggle hide and show dependent on what happened in each step.

Related

Why ajax call send null to servlet? [duplicate]

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;

How to trigger a function in Javascript

If the user doesn't input a correct string it will fail the try. it's fine
My only problem is that I want to send the exception to the error function in the ajax. ATM is sending it to the success.
How do I trigger some sort of error so it sends to the error function in ajax?
public static String call(String input) {
try {
//doesn't matter. it will fail this try
}
} catch (Exception e) {
return e.getMessage(); // I want to send this to the error function in ajax
}
return "Good job";
}
AJAX
$.ajax({
url: '/call',
type: 'get',
data: {input: input},
success: function (resultString) {
//it sends to here instead of error
},
error: function () {
// i want to see it here
}
})
This question is use case dependent, as the correct answer depends on the type of error, business rules and other factors like information exposure.. but to try sending you in the correct direction, you will need to send an HTTP error code, probably a 400 as in https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400
This is an example of a how a servlet can do it (this is also case dependent as the method to use depends on you back end tech):
catch ( MalformedFileUriException e ) {
response.setStatus( HttpServletResponse.SC_BAD_REQUEST );
log.warn( "...", e );
}
catch ( UnsupportedLocaleException e ) {
response.setStatus( HttpServletResponse.SC_BAD_REQUEST );
log.warn( "...", e );
}
catch ( Exception e ) {
response.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
log.error( "...", e );
}
public static String call(String input) {
try {
//doesn't matter. it will fail this try
}
} catch (Exception e) {
echo json_encode(array("status"=>false,"msg"=>e.getMessage())); // I want to send this to the error function in ajax
}
echo json_encode(array("status"=>true,"msg"=>"Good job"));
}
JS
$.ajax({
url: '/call',
type: 'get',
data: {input: input},
success: function (resultString) {
var d = $.parseJSON(resultString);
if(d.status){
//do stuff
}else{
alert(d.msg);//Your alert message
}
}
})
AJAX doesn't catch the error thrown by server in error function. You need to do it manually to let AJAX know if it was a success or an error. You need to use json_encode and set status true or false.
Check in your AJAX if status is false it means the error was thrown from the server.
PS - I don't know the json_encode syntax in JAVA so I have used the syntax of PHP. Please replace it. But you will get the idea from this.
The ajax success or error gets executed when the AJAX call completes successfully or fails respectively. So basically it does not care what result you are returning from backend. if your backend fails to return any data, only then the AJAX will run into an ERROR block. so if you want to distinguish between your try block returning data and error block returning data you have to apply some logic in your success part of AJAX.
So my approach would be to send the data as a list of text and value rather than a string. you can set the [text] part as "OK" when your backend return data from a try block or else you can set the [text] block as "Error" in case of catch block returning. And the [Value] of list would be the desired values.
So conclusion use list<> in place of string as a return type, and set the [Text] and [Value] field as required.

Why is jQuery ajax returning a bogus error callback?

When I visit a page that contains a button which makes a jQuery ajax $.post call for the first time, upon clicking on the button the expected URL is successfully hit and the action sends back the expected JsonResult. HOWEVER, the $.post immediately hits the error callback function before the action even runs (remember though, the action method DOES run, the result is simply not being awaited) and the error messages returned are null or empty strings. In other words, it should have hit the success callback but it hits the error callback instead. Hmmmm.
Here is the resultant alert statement:
": Server error. Could not vacate the locker. Try again."
If I hit the button a second time, again, the expected URL is (also still) hit, but this time the $.post (correctly) waits for the response before making the decision on whether to run the success or the error callback, and it ($.post) correctly calls the success call back function.
Here is the resultant alert statement:
"Locker C18 has been successfully vacated and unassigned."
Why is it doing this?
JavaScript/jQuery
$.post({
url: '#Url.Action("ReclaimAlocker", "Ajax")',
data: {
lockerId: id
},
success: function () {
alert('Locker ' + lockerNumber + ' has been successfully vacated and unassigned.');
location.reload();
},
error: function (a, b, c) {
alert(a.responseText + ' : ' + c + ' Server error. Could not vacate the locker. Try again.');
}
});
MVC Action (in a controller called AjaxController)
[HttpPost]
public JsonResult ReclaimAlocker(long lockerId)
{
var lockerAssignments = _amsDb.LockerAssignments.Where(k => k.Active && k.LockerId == lockerId).ToList();
foreach (var assignment in lockerAssignments)
{
assignment.Active = false;
assignment.DateRemoved = DateTime.Now;
_amsDb.Entry(assignment).State = EntityState.Modified;
}
var locker = _amsDb.Lockers.Find(lockerId);
if (locker != null)
{
locker.Occupied = false;
_amsDb.Entry(locker).State = EntityState.Modified;
}
_amsDb.SaveChanges();
return Json(true, JsonRequestBehavior.AllowGet);
}
Here is the info from the Network tab of Chrome Dev tools:
Name Status Type Initiator Size Time
-----------------------------------------------------------------------
1st attempt
ReclaimAlocker (canceled) xhr jquery.min.js:4 0 B 37ms
LockerAssignments 200 document Other 7.7KB 32ms
All subsequent attempts
ReclaimAlocker 200 xhr jquery.min.js:4 7.7KB 39ms

MVC5 prevent modal window from popping up when returning from controller

I'm having an issue where a modal window pops up in my browser after I return to the View from the controller. Here's what the window says (in Chrome):
It contains the html code from Index.cshtml page.
Here is the code in my controller:
public ActionResult Save(Events changedEvent,FormCollection actionValues)
{
string action_type = actionValues["!nativeeditor_status"];
var eventText = actionValues["text"];
var eventStart = actionValues["start_date"];
var eventEnd = actionValues["end_date"];
try
{
switch (action_type)
{
case "inserted":
if (User.IsInRole("Admin"))
db.Event.Add(changedEvent);
Send(eventText, eventStart, eventEnd);
break;
case "deleted":
//changedEvent = db.Event.SingleOrDefault(ev => ev.Id == source_id);
changedEvent = db.Event.SingleOrDefault(ev => ev.text == eventText);
db.Event.Remove(changedEvent);
break;
default: // update
//changedEvent = db.Event.SingleOrDefault(ev => ev.Id == source_id);
changedEvent = db.Event.SingleOrDefault(ev => ev.text == eventText);
UpdateModel(changedEvent);
break;
}
db.SaveChanges();
}
catch (Exception)
{
action_type = "error";
}
return RedirectToAction("Index", "Home");
}
Here is the code from my Index.cshtml page that handles saving to the database:
function init() {
var dp = new dataProcessor("/Home/Save");
dp.init(scheduler);
dp.setTransactionMode("POST", false);
}
I'm still fairly new to MVC and have completed a few tutorials but I have never ran into this behavior before. I was thinking I have to handle the callback from the controller but all my searching hasn't yielded anything so far. I'm hoping someone from this fine community can point me in the right direction.
Thank you for taking the time to read!
You won't be able to redirect from your C# controller if you are using an AJAX request (your dataProcessor is making an AJAX POST request internally).
You have two options:
1) Not to use your dataProcessor, and make a request to the server using the default C# MVC binding like this: https://stackoverflow.com/a/7856996/3638529. With this method, you will be able to return a RedirectToAction() and the user will be returned correctly, but this will probably change your infrastructure a lot.
2) Change your controller to return the url to redirect.
First change your save method to return something like this:
public ActionResult Save(Events changedEvent,FormCollection actionValues)
{
...
return Json(new {success = true, url = Url.Action("Index", "Home")});
}
Then change your JavaScript method to make something like this when your AJAX request is complete:
function myAwesomeSuccessCallback(response) {
if (response.success) {
window.location = response.url;
}
else {
//show error
}
}
I posted on the dhtmlx forum and I was able to get a solution from one of their support staff. I'm posting his answer in full below:
Hello,
here is what happens in your code
1) when you change something in scheduler (e.g. create/delete/modify event), scheduler sends a POST request to Home/Save, as defined in dataProcessor inside init() function()
2) dataProcessor sends post request and expects the server response to match a certain format of json or xml https://docs.dhtmlx.com/dataprocessor__ ... nsedetails
3) Your Save action outputs the html page instead of the expected response, this line:
return RedirectToAction("Index", "Home");
4) client-side fails to parse it as a valid response and pops up a message.
In order to fix the issue, you need to return a valid response from the Save action, it can be done by replacing your current response - return
CODE: SELECT ALL
RedirectToAction("Index", "Home"); //with this:
return Content(
new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(
new System.Collections.Generic.Dictionary<string, string>
{
{"action", action_type},
{"tid", eventId}
}
)
);
// will send response like this {"action":"updated", "tid":"5"} - which is valid response
Please note "tid" - eventId part, if you insert event into db - you have to send new database event it back to the client. If it's any other operation - you can either return the same id as came from the client or omit "tid" field from the response.
This did the trick for me. Thank you all for your comments and I hope my question helps someone else in the future.

Getting nothing when doing cross domain AJAX request with YQL

I am using the following code to do the cross domain AJAX request with YQL :
function requestCrossDomain( site, callback ) {
function cbFunc(data) {
// If we have something to work with...
alert("inside call back");
if ( data.results[0] ) {
// Strip out all script tags, for security reasons.
// BE VERY CAREFUL. This helps, but we should do more.
data = data.results[0].replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '');
// If the user passed a callback, and it
// is a function, call it, and send through the data var.
if ( typeof callback === 'function') {
callback(data);
}
}
// Else, Maybe we requested a site that doesn't exist, and nothing returned.
else throw new Error('Nothing returned from getJSON.');
}
// If no url was passed, exit.
if ( !site ) {
alert('No site was passed.');
return false;
}
// Take the provided url, and add it to a YQL query. Make sure you encode it!
var yql = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent('select * from html where url="' + site + '"') + '&format=xml&callback=cbFunc';
// Request that YSQL string, and run a callback function.
// Pass a defined function to prevent cache-busting.
$.getJSON( yql, cbFunc );
console.log("outside call back");
}
and calling the above as follow :
requestCrossDomain('http://www.cnn.com', function(results) {
alert(results);
});
When i am running the above code in firefox, although response (in firebug console) is showing the content of website inside callback function (cbFunc) yet it is showing nothing as alert.Also the result of console.log("inside call back") at line 5 is not printing in firebug console.
can anyone suggest me where things are going wrong or any explanation for above ?
btw i have already gone through :
http://tek-insight.blogspot.in/2010/05/cross-domain-ajax-request-proxy-json.html
http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-cross-domain-ajax-request-with-yql-and-jquery/
Possible explanation in related stackoverflow questions.
$.getJSON accepts as callback function for 'success' response. But if error were returned (404, 500, etc) then it will not call this function.
You need to add extra functions in order to catch other scenarios of responses:
$.getJSON( yql, cbFunc)
.done(function() { console.log( "second success" ); })
.fail(function(jqxhr, textStatus, error) { console.log( "error", textStatus, error ); })
.always(function() { console.log( "complete" ); });

Categories

Resources