I have two forms ('table' and 'fields'). The 'fields' form is supposed to pre-populate with options depending on the choice made in 'table', by making an Ajax request.
The data is returning perfectly and actually prepopulates the second form (like it should) if I pass a cut-and-paste example of some returned data to a local variable (see commented line).But for some reason it won't work on the returned object??
Any advice would be appreciated as I am very new to JavaScript and am probably missing something blatantly obvious! I am using the following code:
$(document).ready(function() {
$('select#table').change(function(){
$.getJSON("/ajax_get",{id: $(this).val(), ajax: 'true'}, function(data) {
//var data = [{"optionValue":"address", "optionDisplay": "address"},{"optionValue":"latitude", "optionDisplay": "latitude"},{"optionValue":"longitude", "optionDisplay": "longitude"},];
var $persons = $('#fields').empty();
$.each(data, function() {
$persons.append("<option value=" + this.optionValue + ">" + this.optionDisplay + "</option>");
});
});
});
});
Here's a simplified version of your call that should help you figure it out quickly:
$.getJSON("/ajax_get",{id: $(this).val(), ajax: 'true'}, function(data) {
try {
typeof(data.somethingYouExpect);
/* do your on success work here */
} catch (e) {
alert('There is a good chance the response was not JSON');
}
});
Even when using the regular jQuery $.ajax call, it's important to check to be sure the returned response is in the form you expect. This is as simple as setting a variable like success in your response as true. If you did that, the above example becomes something like this:
var jqxhr = $.getJSON("/ajax_get",{id: $(this).val(), ajax: 'true'}, function(data) {
try {
typeof(data.success); // Will throw if success is not present
if (success == true) {
/* handle success */
} else {
/* handle a request that worked, but the server said no */
}
} catch (e) {
/* The actual HTTP request worked, but rubbish was returned */
alert('There is a good chance the response was not JSON');
console.dir(jqxhr.textResponse);
}
});
Here, we remember the object returned by the $.getJSON call (which is just a shortcut to $.ajax), which allows us to view the actual response sent by the server. I'm willing to bet it's a 404, parser error or something of that sort.
For most things, I usually just use $.ajax mostly out of personal preference, where the error callback passes the xhr object to a common function to examine (did the request return 200? etc). If something explodes, I know exactly what went wrong by briefly looking at the console and can disable debug output in one place.
Related
Let's assume I have a post AJAX call and I want to put returned data into some HTML elements.
$.post(settings.url, function(data) {
$('#someElement').text(data.someData1);
$('#someElement2').text(data.someData2);
});
I'm a back-end developer and it's natural for me that I have to do server-side validation of any piece of data coming from user. Although it's the opposite situation, the code above feels a little bit wrong for me (not validated outside data). But on the other hand, I know what I'm returning from the server.
The question is if is it fine to trust that data returned from (also mine) back-end application will have expected structure, or should I validate somehow every data coming server?
Additional question is if there is some nice method to do such validation? Manual validating of existence of every piece of data seems to be a pain in the neck. Especially for more complex data structure.
Just during writing this question an idea came to my mind. I could use $.extend() just like it's commonly used for setting default options while writing modules/plugins. Something like:
$.post(settings.url, function(data) {
var trustedStructure = $.extend({
someData1: $('#someElement').text(),
someData2: $('#someElement2').text(),
}, data);
$('#someElement').text(trustedStructure .someData1);
$('#someElement2').text(trustedStructure .someData2);
});
That way I could have trusted data with additionally current data as default or any other if I want.
Edit:
Forgot to note. I'm talking about pure JSON data responses. No HTML etc included.
Generally you don't validate the response data, as you said before, the data is returned from your own back-end. What you really need to do is to ensure that you have a proper way to handle exceptions or errors with the information coming from the server.
If you're returning an exception from the server you should have a way in the client-side to figure out that if an error or not.
i.e. returning a specific code like a Rest API or having a JSON structure like this:
// Success
{
"error": false,
"data": {
...
}
}
// Exception
{
"error": true,
"message": "Username already taken",
"type": "warning"
}
If you always return a 200 OK status code:
$.ajax({
...
success: function(response) {
if (response.error) {
alert(response.error.message);
} else {
document.querySelector('#field').value = response.data.text;
}
}
});
The HTML Response Codes are useful when you use promises, you can return a 200 OK for the primary flow (success, done), and 4XX or 5XX if something unusual happen (fail):
$.ajax({
url: 'example.php',
...
})
.done(function(response) { alert(response.data); })
.fail(function(error) { alert(error.message); })
.always(function() { clearFields(); });
Does the data returned from your server contain DOM Elements?
If it doesn't and is a pure text return, you can use a textarea to parse incoming data like this:
var textArea = document.createElement('textarea');
textArea.innerHTML = data;
data = textArea.textContent;
Just try it out and let the server send some <p>, <img> or <script> Elements
I have a form which submits data via AJAX to an external server.
The data which gets sent is then validated and if correct the user can then advance onto the next step of the form.
If the data is not valid, then the server returns an error which is outputted as a JSON object.
I can see the JSON object in FIDDLER.
My aim is to grab that JSON data and output it on the page and notify the user.
Ideally, i would do this as part of an error handler on the AJAX request(found below).
Is this achievable?
PS:
Unfortunately, I can't set up a demo because the link that the data is posted to is only available on my network.
It is also worth pointing out that the error that the back-end script outputs is actually stored in the link that the data is posted to.
AJAX REQUEST:
var setUpVrmData = function() {
$("#getvrmdata").click(function () {
var p_vrm = $('#p_vrm').val();
$.ajax({
dataType: "JSON",
type: "POST",
url: "http://217.35.33.226:8888/l4_site/public/api/v1/BC8F9D383321AACD64C4BD638897A/vdata",
data: {
vrm: p_vrm,
},
success: function(data) {
//Empty the dropdown box first.
$("#p_model").empty();
appendString = "<option value='none'>-- Select your model --</option>";
$.each(data['vehiclemodel'], function (k, v) {
// += concatenate the string
appendString += "<option value='" + k + "'>" + v + "</option>";
});
$("#p_model, #ent_mileage").show();
$('.js-find-my-car').hide();
$('.js-get-price').show();
$("#p_model").append(appendString);
$("#p_model").prop("disabled", false);
$('#skey').val(data['skey']);
},
error: function() {
console.log("We return error!");
}
});
});
The Error function will return an XHR object that you may be able to parse to get the message you want. I don't know what is serving the data so depending on how that's setup your mileage may vary. I've done this using PHP as well as C# and writing to Console, but in both cases I was able to control the returned data.
I used this article : http://encosia.com/use-jquery-to-catch-and-display-aspnet-ajax-service-errors/ as a starting point.
You'll need to update:
error: function() {
console.log("We return error!");
}
to
error: function(xhr, status, error) {
console.log("We return error!");
}
Set a break point there in Firebug to check if an XHR object is passed, if not you'll need to find a way to get it.. You mention you can see the JSON in fiddler, it should be available to you. If it is, just use the eval posed in the article and you should be okay. If not you'll have to go and figure out how to get it, depending on your platform difficulty will vary.
A few things to note, eval is messy and can get you into trouble. In the cases I've done this, I removed the eval in production.
Also as of jQuery 1.8 success error and complete are deprecated. Use done fail and always if you plan on updating jQuery in the future.
jQuery API reference, for reference.
http://api.jquery.com/jquery.ajax/
I am making an ajaxSubmit call to a web service, that will return XML.
When I make a call to the same service using XMLHttpRequest.send, the response is correct.
However if I use:
$(form).ajaxSubmit({
error: function _(response) {
$(iframeEl).remove();
config.error.call(scope, Thunderhead.util.JSON.decode(response));
},
success: function _(response) {
console.log(response);
$(iframeEl).remove();
var result = response;
config.success.call(scope, result);
},
iframe: true
});
This returns the correct XML response, but all tags have been transformed to lowercase.
I've checked the call in the Network tab in the developer console, and the case is correct in there, but when it is returned by the ajaxSubmit, it is lowercase.
Does anyone know what is causing this or how to rectify it?
Are you using Malsups jQuery form plugin
This plugin does a lot of toLowerCase transforms, I've not looked too closely but it does seem to lowercase the tag names of something, so this is probably your culprit.
I'd recommend refactoring to using a simple jQuery.ajax() call instead
$(form).on('submit', function(e) {
var url = $(form).attr('action');
e.preventDefault();
$.ajax( url, {
error: function _(jqXHResponse) {
// your code
},
success: function _(response) {
console.log(response);
// your code
}
});
This might be happening, because js is assuming xml as an answer. There is no difference for most xml-parsers which case is used in xml tag names.
I suggest trying to change response data type.
For example there is such option in jQuery.ajax method: http://api.jquery.com/jquery.ajax/ (named dataType). I would try using "text" dataType if case is really important.
Some further issues arose from this in the end, so just posting my eventual solution in case anyone else has this problem. I'm fairly new to javascript, so this might have been obvious to most, but it might help someone else out.
The success callback can actually take in 3 parameters, the third of which (arg2) is the actual response from the request, without any changes from the Malsups form plugin.
So in the end, the solution was simply to use this third parameter instead of the response parameter.
$(form).ajaxSubmit({
error: function _(response) {
$(iframeEl).remove();
config.error.call(scope, Thunderhead.util.JSON.decode(response));
},
success: function _(response, arg1, arg2) {
console.log(response);
$(iframeEl).remove();
var result = response;
config.success.call(scope, arg2.responseXML);
},
iframe: true
});
I've gotten my form to submit via PHP but I'm struggling a bit with the AJAX. Upon submission, the error always comes up as if res is set to false rather than true. I've tried toying around with the code and searching for my own answer because I do want to learn, but I'm not finding what I need.
May you please point me in the right direction as to what I've done improperly?
Thank you so very much!
The code for your reference:
$('#contact_form').submit(function() {
var this_form = $(this);
$.ajax({
type: 'post',
data: this_form.serialize(),
url: 'scripts/send_email.php',
success: function(res) {
if(res == "true") {
$(this_form)[0].reset();
$(".notice").removeClass("error").text("Thank you for contacting us!").addClass("success").fadeIn("fast");
} else {
$(".notice").text("Please check all fields and try again.").addClass("error").fadeIn("fast");
}
}
});
});
try to ask for:
if(res == true)
instead. Also a good way to avoid this kind of problems is to debug your javascript via firebug or the chrome debugger, if you are using chrome you could add this line to your code:
debugger;
if(res == "true")
and the javascript will stop there so you can inspect the variable and see what's happening. you can open it by going to "options --> tools --> developer tools --> scripts".
Hope this helps :)
In your send_email.php file, echo "success" if it succeed.
Then modify your AJAX call like so :
success: function(data) {
if (data == "success") {do stuff} else {do failure stuff}
}
It appears that your truth comparison is returning false due to the value that res represents. You are checking to make sure it is a string with the value of "true". If not, then trigger else code.
Your success property will only be executed if the AJAX transmission was successful. You will want to set the comparison check to the desired output of send_email.php, i.e. 'Success!' or 'Failure!' to indicate the proper handling.
success(data, textStatus, jqXHR)
A function to be called if the request succeeds. The function gets passed three
arguments: The data returned from the server, formatted according to
the dataType parameter; a string describing the status; and the jqXHR
(in jQuery 1.4.x, XMLHttpRequest) object. As of jQuery 1.5, the
success setting can accept an array of functions. Each function will
be called in turn.
See docs for additional information for handling AJAX requests in jQuery.
success: function(res) {
if (res == "Success!") {
$(this_form)[0].reset();
$(".notice").removeClass("error").text("Thank you for contacting us!").addClass("success").fadeIn("fast");
} else {
$(".notice").text("Please check all fields and try again.").addClass("error").fadeIn("fast");
}
}
I am forced to use data from within the getJSON callback function outside of that function. Have a look:
$('#stars').raty({
score: function() {
var $value = 0;
var $id = <?=$id?>;
$.getJSON("getuserrating.php?id=" + $id, function(data) {
$.each(data, function(key, val) {
$value = val;
});
});
return $value;
},
});
This is what I tried but it failed, the $value is still set to 0, although inside the callback it's definitely set to an actual value. I know why it fails, because the AJAX request is send asynchronously. The problem is, the correct way, doing everything inside the callback, is not possible. As you can see I need to retrieve the JSON object within the raty (a plugin) setup. I would just use $.ajax() and set that to synchronous but the documentation marks this as deprecated for 1.8. I'd rather not introduce a solution that I know will be deprecated in the future.
Is there any way at all to do this? Maybe I just don't see the forest for the trees and there's an easy solution right before me. Thanks in advance :)
Approach is backwards if you need to use ajax to get the score.
Make the ajax call first, then pass the value to score within the ajax success
$.getJSON("getuserrating.php?id=" + $id, function(data) {
/* pseudo code here since I don't know the plugin and it's data requirments*/
var score= data.score;
$('#stars').raty({
score: score
});
});
EDIT: you can still pass the data into a score function this way also
Maybe this (taken from jquery getJSON api doc http://api.jquery.com/jQuery.getJSON/) could work:
// Assign handlers immediately after making the request,
// and remember the jqxhr object for this request
var jqxhr = $.getJSON("example.json", function() {
alert("success");
})
.success(function() { alert("second success"); })
.error(function() { alert("error"); })
.complete(function() { alert("complete"); });
// perform other work here ...
// Set another completion function for the request above
jqxhr.complete(function(){ alert("second complete"); });
Just assign another raty attribute instead of returning.