I am creating a small app to teach myself ASP.NET MVC and JQuery, and one of the pages is a list of items in which some can be selected. Then I would like to press a button and send a List (or something equivalent) to my controller containing the ids of the items that were selected, using JQuery's Post function.
I managed to get an array with the ids of the elements that were selected, and now I want to post that. One way I could do this is to have a dummy form in my page, with a hidden value, and then set the hidden value with the selected items, and post that form; this looks crufty, though.
Is there a cleaner way to achieve this, by sending the array directly to the controller? I've tried a few different things but it looks like the controller can't map the data it's receiving. Here's the code so far:
function generateList(selectedValues) {
var s = {
values: selectedValues //selectedValues is an array of string
};
$.post("/Home/GenerateList", $.toJSON(s), function() { alert("back") }, "json");
}
And then my Controller looks like this
public ActionResult GenerateList(List<string> values)
{
//do something
}
All I managed to get is a "null" in the controller parameter...
Any tips?
Request["values[]"]
I modified my response to include the code for a test app I did.
Update: I have updated the jQuery to set the 'traditional' setting to true so this will work again (per @DustinDavis' answer).
First the javascript:
function test()
{
var stringArray = new Array();
stringArray[0] = "item1";
stringArray[1] = "item2";
stringArray[2] = "item3";
var postData = { values: stringArray };
$.ajax({
type: "POST",
url: "/Home/SaveList",
data: postData,
success: function(data){
alert(data.Result);
},
dataType: "json",
traditional: true
});
}
And here's the code in my controller class:
public JsonResult SaveList(List<String> values)
{
return Json(new { Result = String.Format("Fist item in list: '{0}'", values[0]) });
}
When I call that javascript function, I get an alert saying "First item in list: 'item1'".
FYI: JQuery changed the way they serialize post data.
http://forum.jquery.com/topic/nested-param-serialization
You have to set the 'Traditional' setting to true, other wise
{ Values : ["1", "2", "3"] }
will come out as
Values[]=1&Values[]=2&Values[]=3
instead of
Values=1&Values=2&Values=3
$.ajax({ ..., traditional: true});
will help to revert to traditional serialization.
ints
. When I use traditional: true
, it works, your answer and link explains the why of it. It also works when I use type: "POST"
, without using traditional: true
. Why is that? Could you please elaborate. FYI I am using Asp.Net Mvc.
Thanks everyone for the answers. Another quick solution will be to use jQuery.param method with traditional parameter set to true to convert JSON object to string:
$.post("/your/url", $.param(yourJsonObject,true));
Don't post the data as an array. To bind to a list, the key/value pairs should be submitted with the same value for each key.
You should not need a form to do this. You just need a list of key/value pairs, which you can include in the call to $.post.
In .NET4.5
, MVC 5
Javascript:
https://i.stack.imgur.com/5kTwZ.png
mechanism that does post.
$('.button-green-large').click(function() {
$.ajax({
url: 'Quote',
type: "POST",
dataType: "json",
data: JSON.stringify(document.selectedProduct),
contentType: 'application/json; charset=utf-8',
});
});
C#
Objects:
public class WillsQuoteViewModel
{
public string Product { get; set; }
public List<ClaimedFee> ClaimedFees { get; set; }
}
public partial class ClaimedFee //Generated by EF6
{
public long Id { get; set; }
public long JourneyId { get; set; }
public string Title { get; set; }
public decimal Net { get; set; }
public decimal Vat { get; set; }
public string Type { get; set; }
public virtual Journey Journey { get; set; }
}
Controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Quote(WillsQuoteViewModel data)
{
....
}
Object received:
https://i.stack.imgur.com/pgI2k.png
Hope this saves you some time.
Another implementation that is also working with list of objects, not just strings:
JS:
var postData = {};
postData[values] = selectedValues ;
$.ajax({
url: "/Home/SaveList",
type: "POST",
data: JSON.stringify(postData),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function(data){
alert(data.Result);
}
});
Assuming that 'selectedValues' is Array of Objects.
In the controller the parameter is a list of corresponding ViewModels.
public JsonResult SaveList(List<ViewModel> values)
{
return Json(new {
Result = String.Format("Fist item in list: '{0}'", values[0].Name)
});
}
As I discussed here ,
if you want to pass custom JSON object to MVC action then you can use this solution, it works like a charm.
public string GetData() {
// InputStream contains the JSON object you've sent
String jsonString = new StreamReader(this.Request.InputStream).ReadToEnd();
// Deserialize it to a dictionary
var dic =
Newtonsoft.Json.JsonConvert.DeserializeObject < Dictionary < String,
dynamic >> (jsonString);
string result = "";
result += dic["firstname"] + dic["lastname"];
// You can even cast your object to their original type because of 'dynamic' keyword
result += ", Age: " + (int) dic["age"];
if ((bool) dic["married"])
result += ", Married";
return result;
}
The real benefit of this solution is that you don't require to define a new class for each combination of arguments and beside that, you can cast your objects to their original types easily.
You can use a helper method like this to facilitate your job:
public static Dictionary < string, dynamic > GetDic(HttpRequestBase request) {
String jsonString = new StreamReader(request.InputStream).ReadToEnd();
return Newtonsoft.Json.JsonConvert.DeserializeObject < Dictionary < string, dynamic >> (jsonString);
}
You can setup global parameter with
jQuery.ajaxSettings.traditional = true;
The answer helped me a lot in my situation so thanks for that. However for future reference people should bind to a model and then validate. This post from Phil Haack describes this for MVC 2. http://haacked.com/archive/2010/04/15/sending-json-to-an-asp-net-mvc-action-method-argument.aspx
Hope this helps someone.
Success story sharing
dataType: 'JSON'
causes jQuery to attempt to parse the response as JSON, and will error if it is not valid JSON.dataType: 'json'
is for the return type and is not required to send array to Action.contentType: "application/json; charset=utf-8"
, is the one, but in some cases like this is not required.var postData = { id: 45, [{myClassProp1: 1, myClassProp2: 2}, {}...], anotherParam: "some string" };