I'm trying to post my form data which is model bound to a controller via an Ajax request however, the controller is showing that the data is null, despite the request header showing the data is being sent.
Code is below. I've tried data: JSON.stringify(form) which results in a null model whereas the below results in a model with null data.
View
$(document).on('click', '#saveData', function () {
if ($('#form').valid()) {
var form = $('#form').serialize();
$.ajax(
{
url: '#Url.Action("CreateClient", "Processors")',
type: 'POST',
cache: false,
async: false,
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(form)
})
.success(function (response)
{ alert(response); })
.error(function (response)
{ alert(response); });
}
});
Controller
public ActionResult CreateClient(ModelData form)
{
if (form == null || !ModelState.IsValid)
{
return Json("Error");
}
return Json("Success");
}
There are two problems with your approach.
If your model class ModelData is, for example,
class ModelData {
public string Foo {get;set;}
public string Bar {get;set;}
}
the appropriate data to send is {foo:"foo1", bar:"bar1"}, or eventually {Foo:"foo1", Bar: "bar1"}, depending on how you have configured your serialization - as you have specified contentType 'application/json'.
However, you are reading your form using jquery serialize(). This method returns a string, on the form "foo=foo1&bar=bar1", appropriate for contentType 'application/x-www-form-urlencoded'. So you have to make up your mind on in what format you want to send the data. If you want to continue to use serialize() to obtain the data from the DOM, use 'application/x-www-form-urlencoded' instead.
Secondly, JSON.stringify() will create a JSON string from an object. A string is an object, too. So passing a string to this function will wrap the string in a string, which doesn't make much sense: The data will be something like "\"foo=foo1&bar=bar1\"". In the same manner, the jQuery ajax function will expect an object for it's data parameter when contentType is 'json', so if you convert your object to a string before, it will be sent just as that: a string. Basically, whatever contentType you end up choosing for your request, don't use JSON.stringify for your data parameter.
TL;DR: To get this working, use the default contentType or declare it explicitly as per below, and pass the form variable as-is:
var form = $('#form').serialize();
$.ajax(
{
//(...)
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
data: form,
//(...)
Related
I am trying to get value based on 2 parameters, below is my function where I added my 2 parameters in JSON stringify :
function GetItemLocationOnHand(itemId, locationId) {
var data = JSON.stringify({
itemId: itemId,
locationId: locationId
});
$.ajax({
async: true,
type: 'GET',
dataType: 'JSON',
contentType: 'application/json; charset=utf-8',
data: data,
url: 'getItemInventory3',
success: function (data) {
$("#txtInventory3").val(parseFloat(data).toFixed(2));
},
error: function () {
alert("Error")
}
});
}
Below is my code in my controller to retrieve the data I want based on these two parameters :
[HttpGet]
public JsonResult GetItemLocationOnHand(int itemId, int locationId)
{
var itemLocQuantity = objDB.ItemLocationDatas.Single(items => items.ItemId == itemId && items.LocationId == locationId).Quantity;
return Json(itemLocQuantity, JsonRequestBehavior.AllowGet);
}
Upon calling this function via below on change code, I can't seem to get my data and is always returning the error.. If I only have 1 parameter, then no error encountered.
Please advise what went wrong when trying to pass 2 parameters.
$("#LocationId").change(function () {
var itemId = $("#ItemId").val();
var locationId = $("#LocationId").val();
GetItemLocationOnHand(itemId, locationId)
});
Issue solved by doing the following :
added correct URL which is GetItemLocationOnHand
removed Stringify and used var data = ({ itemId: itemId, locationId:
locationId });
thanks a lot to Freedom and Reflective and others for your comments!
function GetItemLocationOnHand(itemId, locationId) {
var data = ({ itemId: itemId, locationId: locationId });
$.ajax({
async: true,
type: 'GET',
dataType: 'JSON',
contentType: 'application/json; charset=utf-8',
data: data,
url: 'getItemLocationOnHand',
success: function (data) {
$("#txtInventory3").val(parseFloat(data).toFixed(2));
},
error: function () {
alert("Error")
}
});
}
Just to avoid some misunderstanding how AJAX GET works and setting some parameters which you don't have to set (i.e. you are still not so deep into jQuery AJAX) you may use the shortcut they also implemented i.e. $.get so your request will look as simple as that and you can't get wrong as it will use the proper defaults for GET. If you want the response to be treated as JSON, just set Content-type of your response headers (from backed) to application/json. This will be checked by jQuery AJAX response handler and it will parse the incoming data as JSON.
var data = {itemId: 1, locationId: 2 };
$.get('GetItemLocationOnHand', data, function (data) {
$("#txtInventory3").val(parseFloat(data).toFixed(2));
}).fail(function (jqXHR, textStatus ) {
alert(`Error = ${jqXHR.status} ${textStatus}`);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
See my example below. This works for me when doing ajax requests to a MVC controller with multiple params.
Below is my MVC controller action with multiple params.
// GET
[HttpGet]
public ActionResult Index(string referenceID, int typeID, int supplierID, bool isArchived)
{
// Do CODE here
}
Below is my Ajax request that I use to get or post. Depending on your needs. I use data type 'JSON' and format my data as a JSON object.
var formData = {referenceID: 'Test', typeID: 3, supplierID: 2, isArchived: false};
$.ajax({
type: 'GET',
cache: false,
url: getActionUrl, // url: domain/controller/action |or| domain/area/controller/action
dataType: 'json',
contentType: 'application/json; charset=utf-8',
headers: headers, // ignore if not needed. I use it for __RequestVerificationToken
data: formData,
success: function (data, status, xml) {
// do something with the data
},
error: function (xml, status, error) {
console.log(xml)
// do something if there was an error
},
complete: function (xml, status) {
}
});
I think your issue might be that you are using 'JSON.stringify'. It could be interpreting your JSON string as a single parameter input and not two separate parameters.
Please see below snippets from documentation. https://api.jquery.com/jquery.ajax/
If json is specified, the response is parsed using jQuery.parseJSON before being passed, as an object, to the success handler. The parsed JSON object is made available through the responseJSON property of the jqXHR object.
The data option can contain either a query string of the form key1=value1&key2=value2, or an object of the form {key1: 'value1', key2: 'value2'}. If the latter form is used, the data is converted into a query string using jQuery.param() before it is sent. This processing can be circumvented by setting processData to false. The processing might be undesirable if you wish to send an XML object to the server; in this case, change the contentType option from application/x-www-form-urlencoded to a more appropriate MIME type.
We have a situation where we would like controller to get First parameter as json (model) as second parameter as some additional data other than model (such as Flag, source control from where event is driven etc.), we have tried tweaking with jQuery but all ended up error shown in the browser inspect element.
We have our controller typically like this:
public async Task<ActionResult> Foo(Bar b, string additionaldata)
{
if (additionaldata="Deleted")
{
}
else if (additionaldata="Favorite")
{
}
}
And inside view its something like this:
$("#delete").click(function () {
$.ajax({
url: "/Index/Foo",
type: "POST",
data: $("#myform").serialize(),
dataType: "json"
}).done(function (model) {
$("#Foo_Id").val(model.Foo.Id);
});
});
As far as model is concerned, this jQuery is working fine, but as far as we try to add some additional parameter, we are clueless.
Please suggest how we may pass it.
On option is to use FormData to build the model and add additional data
var formdata = new FormData($('#myform').get(0)); // serialize the form
formdata.append('additionaldata', 'Favorite'); // add additional properties
$.ajax({
url: '#Url.Action("Index", "Foo")',
type: 'POST',
data: formdata,
processData: false,
contentType: false,
});
In MVC, why does returning Content sometimes fail in the Ajax callback, while returning Json works, even for simple string objects?
Even when it fails, the data is still available if you were to access it in the always callback...
Update:
When I set the contentType in the ajax call to text/xml the response will no longer enter the error message.
AJAX:
$.ajax({
cache: false,
type: "GET",
contentType: "application/json; charset=utf-8",
dataType: 'json',
url: "/MyController/GetFooString",
data: { },
success: function (data) {
alert(data);
},
error: function (xhr, ajaxOptions, thrownError) {
alert("Ajax Failed!!!");
}
}); // end ajax call
Controller Action That Fails (Sometimes)
Even when it fails, the data is still available.
public ActionResult GetFooString()
{
String Foo = "This is my foo string.";
return Content(Foo);
} // end GetFooString
Controller Action That Always Works
public ActionResult GetFooString()
{
String Foo = "This is my foo string.";
return Json(Foo, JsonRequestBehavior.AllowGet);
} // end GetFooString
Using Content(Foo); sends a response that doesn't have the mime type header. This happens because you're not setting ContentType when using this overload. When the Content-Type is not set, jQuery will try to guess the content type. When that happens, whether it can successfully guess or not depends on the actual content and underlying browser. See here:
dataType (default: Intelligent Guess (xml, json, script, or html))
Json(...) on the other hand explicitly sets the content type to "application/json" so jQuery knows exactly what to treat the content as.
You can get consistent result from Content if you use the 2nd overload and specify a ContentType:
return Content(Foo, "application/json"); // or "application/xml" if you're sending XML
But if you're always dealing with JSON, then prefer using JsonResult
return Json(Foo, JsonRequestBehavior.AllowGet);
Inside my controller there is JsonResult action which returns me a list of House object.
I want onclick using ajax to retrieve these data and to display json data inside my view.
Inside firebug I'm able to see proper Response and Json result but I dont know how to display inside my view.
function GetTabData(xdata) {
$.ajax({
url: ('/Home/GetTabData'),
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({ id: xdata }),
success: function (result) {
// tried with these but it doesnt work
// result = jQuery.parseJSON(result);
// alert(result.Title);
},
error: function () { alert("error"); }
});
}
public JsonResult GetTabData()
{
...
var temp = getMyData...
return Json(temp, JsonRequestBehavior.AllowGet);
}
// View page
<div id="showContent">
// Json data should appear here
</div>
Inside firebug JSON tab when success:function(result) is empty
I have following data:
Id 149
PropertyType "Apartment"
StreetNumber "202B"
CityName "Sidney"
Title "My test data"
success: function (json) {
var data = null;
$.each(json.items,function(item,i){
data = '<div>'+item.Id+ ' ' + item.CityName +'</div>';
$("#showContent").append(data);
});
}
First of all, you can specify the dataType attribute in your ajax call to 'json' and then don't have to decode the json response again -
dataType: 'json'
Then, you don't need to use parseJSON. Simply use result.Title etc.
success: function (result) {
alert(result.Title);
var showContent = $('#showContent');
showContent.html(result.Id+','+result.Title);
},
EDIT: As Mukesh said, you can have the ajax function return json without using any extra decoding.
The ajax call result is already an object. You can do whatever you want with it it inside the success function.
For example you could create a table of the information dynamically inside the function, or send the data to another function by calling the function inside that success function. Once you leave the success function, the data is not usable anymore.
Access the data object like any object (data.someProperty).
There is quite a lot of helpful information on MVC model binding.
My problem stems from the fact that I am trying to avoid creating strongly typed data in my MVC application as it mostly needs to act as a data router.
Basically, I have a set of fields on a page, with a class 'input', that I can gather with jQuery('.input'), iterate over and stuff into a javascript object. I then send this to my ASP.NET MVC controller:
var inputData = my_serialize( $('input');
$.ajax({
type:'POST',
url: '/acme/Ajax/CaptureInput',
dataType: "json",
data: { inputData: JSON.stringify(inputData) },
success: Page_Response_RegisterAndDeposit,
error: Page_AjaxError
});
On the C# side, I have
public JsonResult CaptureInput(string inputDataAsJsonString)
{
JavaScriptSerializer JSON = new JavaScriptSerializer();
object inputData = JSON.DeserializeObject(inputDataAsJsonString);
This seems like a wasteful level of indirection, I'd prefer to pass the data as contentType:application/json and have CaptureInput accept an object or IDictionary or even a dynamic.
You could use the serializeArray method. Let's suppose that you have a form containing the input elements which could be of any type and you want to invoke the following controller action:
public ActionResult CaptureInput(Dictionary<string, string> values)
{
...
}
here's how you could proceed:
<script type="text/javascript">
var values = $('form').serializeArray();
var data = {};
$.each(values, function (index, value) {
data['[' + index + '].key'] = value.name;
data['[' + index + '].value'] = value.value;
});
$.ajax({
url: '#Url.Action("CaptureInput")',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(data),
success: function (result) {
alert('success');
}
});
</script>
Not exactly what you're after but maybe the resolution of this issue would give you a partial workaround, by allowing you to bind to a simple wrapper object with an embedded Dictionary. It might even allow binding direct to a Dictionary. Not sure...
You might also need to explicitly set the json ContentType header in your $.ajax call
"JSON model binding for IDictionary<> in ASP.NET MVC/WebAPI"