Use jQuery to post data to MVC action method
Solution 1
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.
Solution 2
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.
Solution 3
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"
})
})
})
Solution 4
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!
LP13
Updated on July 22, 2022Comments
-
LP13 almost 2 years
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 JSONstringify
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
toJsonResult
.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 }
-
Admin over 8 yearsYou do not need to specify
[HttpPost]
(the ajax options includetype: "POST",
). You do not need to changeActionResult
toJsonResult
(JsonResult
isActionResult
). You do not need[FromBody]
(that relates to webapi) -
Michael Crook over 8 yearsWhy not specify [HttpPost] I'm pretty sure (not completely) that save isn't a method name that MVC can automatically convert. JsonResult isn't needed, but it makes more sense as it is returning a JsonResult. But maybe your correct as he is hitting the method, it's just nothings coming along with it. Try looking into what the JS creats with JSON.stringify maybe that's not working and your passing null up
-
Admin over 8 yearsYou can (and really should) include the
[HttpPost]
attribute, but its not required in this case because of the ajax call. Ditto forJsonResult
(you can, and probably should, but its not necessary). OP's issues are not related to anything you have in your answer. Could be the url is incorrect (it should be/Working/Save"
) or the model has only fields (noget; set;
) but who knows until more information is provided. And in any case, OP should removecontentType:
and notstringify
the data -
Admin over 8 yearsOP is submitting JSON. That's what
data: JSON.stringify(dataToPost),
does! -
Racil Hilan over 8 years@StephenMuecke Thank you for your notice. Of course, you're right about what that line does, but I meant to say that he shouldn't be submitting Json. I should've included that line in my answer. I will update my answer.
-
Michael Crook over 8 yearsOk, it should work for you now :) just watch your browsers console as I think your routing might differ to my setup, I had to chagne the url of the post in my solution
-
LP13 over 8 years@RacilHilan thanks for your reply. Model properties does match with the name of the html control and they are string which is nullable. Also how does it matter how the action method is processing model inside after it receives model, because for action method it will be simple C# object?
-
Racil Hilan over 8 yearsHmm, you have a good point about the processing afterwards. Like I said, we don't see your action code so it's all guessing there. But apart from that, my answer still stands, so have you tried the solution I gave above?
-
LP13 over 8 years@MichaelCrook thanks! That is how we are doing right now by creating a json object manually and posting it and its working. However now consider if we have to post large object it will be time consuming process. that why i would to seralize the form and post it. Also note that type of button is not "submit"
-
LP13 over 8 yearsAlso note that type of the input is not "Submit"
-
Racil Hilan over 8 yearsYes of course, because you're submitting it using Ajax. My suggestion was that you Ajax submission should mimic a standard form submission.
-
Michael Crook over 8 yearsThe reason why is because $.serialize doesn't convert to JSON, it converts it to somthing you can post in a URI (www.yoursite.com/post?PersonName=a&Address=b&States=OK&States=OH&Status=3 see this: jsfiddle.net/n7rpzr6x If you want to convert a form automagically into JSON have a look into this stackoverflow question, the answer is awesome (with over 1000 upvotes) stackoverflow.com/questions/1184624/…
-
Michael Crook over 8 yearsHA! Very smart, didn't even consider just submitting as form data. FYI, this solution sends data to the server in this format: PersonName=a&Address=b&States=TX&States=OK&Status=2 Rather than JSON. But that is perfectly fine :).. You will find though that as your forms get more complex, manually constructing a JS Object (like in my answer) will work better as automagic stuff like $.serialize doesn't customize very well.
-
Michael Crook over 8 yearsOh and you can also post it as a part of the body as form data, like the answer above does
-
LP13 over 8 years@MichaelCrook thanks. Now your answer started me thinking again :) So far we were submitting small amount of data (5-6 fields) and thats why we were constructing json object by hand. For complex page (30-40 inputs + grids) i didn't want to construct json object by hand. i thought Form serialization will do the trick. Do we know any specific issues with $.serialize method?
-
Michael Crook over 8 yearsjust that if your way of displaying the data to the user doesn't map strait from $.serialize to your ASP.NET model you will be forced to map it to an intermediary model like I did. If your starting to get big forms like that though, may I recoemend that you learn Knockout.js, its a data binding framework for web. That way your HTML is bound to your JS objects, then you just JSON.stringify your js models and it will automatically have all your form data already ready to rock!
-
Admin over 8 years@MichaelCrook, That's nonsense. Using
.serialize()
will always work correctly if the view is constructed using the HtmlHelpers based on a model. -
Admin over 8 years@user3862378, Since Tieson T. provided the correct answer previously, that's the one you should have accepted, or at the very least up-voted it