Reputation: 34149
I'm trying to post data using jQuery Ajax to MVC action using the approach below. But inside the controller all model properties are always null
. Not sure what I'm missing here.
.CSHTML
<form id="MyForm">
<input name="PersonName" type="text" />
<input name="Address" type="text" />
<select name="States" multiple="multiple">
<option value="TX">Texas</option>
<option value="OK">Oklahoma</option>
<option value="OH">Ohio</option>
</select>
<select name="Status">
<option value="1">Active</option>
<option value="2">Deleted</option>
<option value="3">Pending</option>
</select>
<input type="button" value="Save" id="Save" />
JavaScript
$(function () {
$("#Save").click(function (e) {
var dataToPost = $("#MyForm").serialize()
$.ajax(
{
type: "POST",
data: JSON.stringify(dataToPost),
url: "Working/Save",
contentType: 'application/json; charset=utf-8'
})
})
})
Controller
public class WorkingController : Controller
{
// GET: Working
public ActionResult Index()
{
return View();
}
public ActionResult Save(WorkingModel model)
{
// All model properties are null here????
return Json("Success");
}
}
Model
public class WorkingModel
{
public string PersonName { get; set; }
public string Address { get; set; }
public string[] States { get; set; }
public string Status { get; set; }
}
EDIT1
I have added the model above. Here the serialized data and JSON stringify
data when I click on save.
Serialized data
"PersonName=Foo&Address=123+Test+Drive&States=TX&Status=1"
After JSON.Stringify
"\"PersonName=Foo&Address=123+Test+Drive&States=TX&Status=1\""
I have tried adding HttpPost
attribute and [FromBody]
attribute with no luck.
I don't think I have to change the return type from ActionResult
to JsonResult
.
Also the URL is correct because the debugger is hitting inside the action method where I can QuickWatch
the model properties.
Note that it works if I create JSON object and post it like below:
var dataToPost = {
PersonName:'Foo',
Address: '123 Test Drive',
State: 'TX',
Status: 1
}
Upvotes: 10
Views: 69334
Reputation: 25361
I think that you should submit standard HTML form data rather than JSON data. Hence change the lines:
data: JSON.stringify(dataToPost),
contentType: 'application/json; charset=utf-8'
to
data: dataToPost,
contentType: 'application/x-www-form-urlencoded; charset=UTF-8'
Note: You can also omit the second line because that is the default contentType
for $.ajax
According to jQuery documentation.
EDIT 1 This is in response to your comment and edit.
What I was trying to tell you is that the data that your Ajax is sending must match how you're processing the data received by your action. The reason that your model properties are null
is that those two don't match.
You did not post the code for your action, so we have no idea how you're processing the data, but now from your edit 1, it seems you're processing the data received as JSON data, because it worked when you sent it real JSON data.
So you have to do one of two things:
1- Send real JSON data: Simply using JSON.stringify
does not mean your data is now appropriate JSON data. As you found, JSON.stringify
simply wrapped your string with quotation marks making it a valid JSON string, that's all. But that's not what your action is expecting, it is expecting a JSON object. To send a JSON object, you probably need to write a function that takes the form fields one by one and build a JSON object, then call this function instead of JSON.stringify
.
2- Send standard form data: That's what I was suggesting in my answer above. To make it work, simply delete all the code in your action that is processing it as a JSON object. MVC is designed to process standard form data by default, so you don't need any additional processing. Simply send it standard form data and it will work.
Note: Ajax does not need to be sending/receiving data in JSON format. JSON format is very useful for exchanging data in many scenarios, but you choose the format that suits your specific scenario. For example, your action is sending back a JSON object just for the result: return Json("Success")
. If you only want to send simple result (success vs. failure), you can return a simple string (e.g. return "Success"
) or even a boolean/integer (e.g. return "True"
or return "1"
). Jason objects need extra processing to parse them from the string. While this processing is very fast and efficient, it is still a bit faster to parse and process simple data types like string, boolean, or integer if you don't need to send additional info.
Upvotes: 7
Reputation: 21239
Your JavaScript/jQuery code can be significantly simplified, which might be the best route to go:
$(function () {
$("#MyForm").on('submit', function (e) {
e.preventDefault() // prevent the form's normal submission
var dataToPost = $(this).serialize()
$.post("Working/Save", dataToPost)
.done(function(response, status, jqxhr){
// this is the "success" callback
})
.fail(function(jqxhr, status, error){
// this is the ""error"" callback
})
})
})
You should handle the onsubmit
event of the form, rather than the onclick
event of the button - it's possible for something other than the button to cause the form to be submitted. In this case, we want to prevent the form's default submit behavior, since we're submitting the form with AJAX.
.serialize()
already handles encoding the form correctly, so you don't need to JSON-encode the form values. Doing so is most likely the reason that the modelbinder isn't rebuilding the model when processing the request.
$.post
is a helper function that wraps the common setup work you need for $.ajax
- the version shown here wants the URL to POST to, and the data to POST. If your jQuery code is in a script element within a View, then you probably want to use the Url.Action()
helper - it will build the correct URL based on your routing rules. If you elect to go that route, you would use something similar to:
$.post('@Url.Action("Save", "Working")', dataToPost)
Then, we handle the successful response (anything with a HTTP-200 status code) and the failed response (anything else, basically) using the relevant helpers. What you do in those helpers is up to you.
Upvotes: 14
Reputation: 34149
i just have to remove the content type from post and dont stringify it and it worked
$(function () {
$("#Save").click(function (e) {
var dataToPost = $("#MyForm").serialize()
$.ajax(
{
type: "POST",
data: dataToPost,
url: "Working/Save"
})
})
})
Upvotes: 5
Reputation: 1535
Move previous answer text to pastebin as I was wrong, answer is as follows:
Just read your edit, your problem is JSON thing looks funny: "\"PersonName=Foo&Address=123+Test+Drive&States=TX&Status=1\"" That will not translate into WorkingModel.
My recomendation is to create a custom JS object and post it. I just fired up a VS MVC project and made it, it all is working :)
$(function() {
$("#Save").click(function(e) {
var personName = $("[name='PersonName']").val();
var address = $("[name='Address']").val();
var states = $("[name='States']").val();
var status = $("[name='Status']").val();
var dataToPost = {
PersonName: personName,
Address: address,
States: states,
Status: status
};
$.ajax(
{
type: "POST",
data: JSON.stringify(dataToPost),
url: "Save",
contentType: 'application/json; charset=utf-8'
});
});
});
Hope this helps!
Upvotes: 1