Passing A List Of Objects Into An MVC Controller Method Using jQuery Ajax
Asked Answered
C

18

132

I'm trying to pass an array of objects into an MVC controller method using jQuery's ajax() function. When I get into the PassThing() C# controller method, the argument "things" is null. I've tried this using a type of List for the argument, but that doesn't work either. What am I doing wrong?

<script type="text/javascript">
    $(document).ready(function () {
        var things = [
            { id: 1, color: 'yellow' },
            { id: 2, color: 'blue' },
            { id: 3, color: 'red' }
        ];

        $.ajax({
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            type: 'POST',
            url: '/Xhr/ThingController/PassThing',
            data: JSON.stringify(things)
        });
    });
</script>

public class ThingController : Controller
{
    public void PassThing(Thing[] things)
    {
        // do stuff with things here...
    }

    public class Thing
    {
        public int id { get; set; }
        public string color { get; set; }
    }
}
Corelation answered 6/11, 2012 at 0:1 Comment(4)
You can try JavaScriptSerializer.Deserialize Method (String, Type)Birdlime
Your data is a string, yet your method accepts an array. Change your method to accept a string, then deserialize it within the method.Marron
Your code is correct. I tested it and it worked using MVC 4. Please provide more data to figure it out.Cilka
This is great stuff but what if you need not just a list of strings to pass but need to include a separate id associated with the list of strings? So like, group id, list of groups under group id.Teasley
C
213

Using NickW's suggestion, I was able to get this working using things = JSON.stringify({ 'things': things }); Here is the complete code.

$(document).ready(function () {
    var things = [
        { id: 1, color: 'yellow' },
        { id: 2, color: 'blue' },
        { id: 3, color: 'red' }
    ];      
    
    things = JSON.stringify({ 'things': things });

    $.ajax({
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        type: 'POST',
        url: '/Home/PassThings',
        data: things,
        success: function () {          
            $('#result').html('"PassThings()" successfully called.');
        },
        failure: function (response) {          
            $('#result').html(response);
        }
    }); 
});


public void PassThings(List<Thing> things)
{
    var t = things;
}

public class Thing
{
    public int Id { get; set; }
    public string Color { get; set; }
}

There are two things I learned from this:

  1. The contentType and dataType settings are absolutely necessary in the ajax() function. It won't work if they are missing. I found this out after much trial and error.

  2. To pass in an array of objects to an MVC controller method, simply use the JSON.stringify({ 'things': things }) format.

Corelation answered 6/11, 2012 at 16:38 Comment(15)
I was having the same problem and adding the contentType fixed it. Thanks!Astroid
Two things to note: JSON.stringify and specifying 'contentType'.Umbria
Crud. Still not working for me. my request URL is http://localhost:52459/Sales/completeSale?itemsInCart=[{"ItemId":1,"Quantity":"1","Price":3.5}] and Sales.completeSale is public ActionResult completeSale(ItemInCart[] itemsInCart), annotated as a HttpGet.Bristle
Apparently type:Post is required too! Data doesn't go through to a Controller otherwise.Mellifluous
for whatever reason I had to to just use data: JSON.stringify(things),Inurbane
I am looking for something similar. Can you let me know how to do.. #36348058Haemachrome
I was using the same approach to pass list to controller. However it was working since I was missing "contentType" in ajax call. Thanks @Corelation to provide complete example.Resting
dataType is not necessary. If its omitted, the ajax function will work it out based on the return dataGrievance
Surprised that you couldn't drop dataType and stringify similar to the newer answer from lanternmarsh. Also, word to wise , make sure your string values aren't nulls in JavaScript-land. That threw me for a long loop, though I don't think it's the first time. (◔_◔)Halland
For aspnetcore 2, remember to add [FromBody] in your controller function otherwise it won't work.Valdis
I had everything same except I used data: JSON.stringify(things) because things = JSON.stringify({ 'things': things }); did not work for me.Transsonic
this works on WEB API with little changes. thanks.Liegeman
my issue.. #57085768Haemachrome
vadims already mentioned this, but make sure you use type:PostSubsidiary
Be very careful not to initialise your variables in your controller. So public int Id { get; set; } will work, but public int id = 0 won't. Just wasted an hour or so tracking this down!Sixtasixteen
D
46

Couldn't you just do this?

var things = [
    { id: 1, color: 'yellow' },
    { id: 2, color: 'blue' },
    { id: 3, color: 'red' }
];
$.post('@Url.Action("PassThings")', { things: things },
   function () {
        $('#result').html('"PassThings()" successfully called.');
   });

...and mark your action with

[HttpPost]
public void PassThings(IEnumerable<Thing> things)
{
    // do stuff with things here...
}
Distillery answered 26/3, 2015 at 16:28 Comment(4)
This should be the best answer. The JSON.stringify should not be used in this caseDisavow
This is not working for me..I am using [HttpPost] public int SaveResults(List<ShortDetail> model) {} and $.post("@Url.Action("SaveResults", "Maps")", {model: dataItems}, function (result) { });Together
It worked for me. Absolutely the best answer. I don't know why the Halcyon implementation didn't work. The PassThings function was invoked but the 'things' input variable was empty even if it was filled in the javascript just before the call.Mondragon
can we add file upload to it.Goal
L
25

I am using a .Net Core 2.1 Web Application and could not get a single answer here to work. I either got a blank parameter (if the method was called at all) or a 500 server error. I started playing with every possible combination of answers and finally got a working result.

In my case the solution was as follows:

Script - stringify the original array (without using a named property)

    $.ajax({
        type: 'POST',
        contentType: 'application/json; charset=utf-8',
        url: mycontrolleraction,
        data: JSON.stringify(things)
    });

And in the controller method, use [FromBody]

    [HttpPost]
    public IActionResult NewBranch([FromBody]IEnumerable<Thing> things)
    {
        return Ok();
    }

Failures include:

  • Naming the content

    data: { content: nodes }, // Server error 500

  • Not having the contentType = Server error 500

Notes

  • dataType is not needed, despite what some answers say, as that is used for the response decoding (so not relevant to the request examples here).
  • List<Thing> also works in the controller method
Locoweed answered 10/6, 2018 at 19:45 Comment(0)
S
14

Formatting your data that may be the problem. Try either of these:

data: '{ "things":' + JSON.stringify(things) + '}',

Or (from How can I post an array of string to ASP.NET MVC Controller without a form?)

var postData = { things: things };
...
data = postData
Sylas answered 6/11, 2012 at 0:51 Comment(1)
Your code is close, but it doesn't work. I was able to get the code working thanks to your suggestion. See my answer above.Corelation
T
10

I have perfect answer for all this : I tried so many solution not able to get finally myself able to manage , please find detail answer below:

       $.ajax({
            traditional: true,
            url: "/Conroller/MethodTest",
            type: "POST",
            contentType: "application/json; charset=utf-8",
            data:JSON.stringify( 
               [
                { id: 1, color: 'yellow' },
                { id: 2, color: 'blue' },
                { id: 3, color: 'red' }
                ]),
            success: function (data) {
                $scope.DisplayError(data.requestStatus);
            }
        });

Controler

public class Thing
{
    public int id { get; set; }
    public string color { get; set; }
}

public JsonResult MethodTest(IEnumerable<Thing> datav)
    {
   //now  datav is having all your values
  }
Torques answered 27/7, 2015 at 14:42 Comment(1)
You should have more upvotes: traditional: true is the recommended way on the Jquery websitePounce
B
7

The only way I could get this to work is to pass the JSON as a string and then deserialise it using JavaScriptSerializer.Deserialize<T>(string input), which is pretty strange if that's the default deserializer for MVC 4.

My model has nested lists of objects and the best I could get using JSON data is the uppermost list to have the correct number of items in it, but all the fields in the items were null.

This kind of thing should not be so hard.

    $.ajax({
        type: 'POST',
        url: '/Agri/Map/SaveSelfValuation',
        data: { json: JSON.stringify(model) },
        dataType: 'text',
        success: function (data) {

    [HttpPost]
    public JsonResult DoSomething(string json)
    {
        var model = new JavaScriptSerializer().Deserialize<Valuation>(json);
Benelux answered 19/7, 2017 at 4:50 Comment(1)
To make this work, follow the format of the Ajax call closely.Cyprian
T
5

This is how it works fine to me:

var things = [
    { id: 1, color: 'yellow' },
    { id: 2, color: 'blue' },
    { id: 3, color: 'red' }
];

$.ajax({
    ContentType: 'application/json; charset=utf-8',
    dataType: 'json',
    type: 'POST',
    url: '/Controller/action',
    data: { "things": things },
    success: function () {
        $('#result').html('"PassThings()" successfully called.');
    },
    error: function (response) {
        $('#result').html(response);
    }
});

With "ContentType" in capital "C".

Terret answered 21/5, 2020 at 3:0 Comment(1)
you save my dayGittel
P
4

This is working code for your query,you can use it.

Controler

    [HttpPost]
    public ActionResult save(List<ListName> listObject)
    {
    //operation return
    Json(new { istObject }, JsonRequestBehavior.AllowGet); }
    }

javascript

  $("#btnSubmit").click(function () {
    var myColumnDefs = [];
    $('input[type=checkbox]').each(function () {
        if (this.checked) {
            myColumnDefs.push({ 'Status': true, 'ID': $(this).data('id') })
        } else {
            myColumnDefs.push({ 'Status': false, 'ID': $(this).data('id') })
        }
    });
   var data1 = { 'listObject': myColumnDefs};
   var data = JSON.stringify(data1)
   $.ajax({
   type: 'post',
   url: '/Controller/action',
   data:data ,
   contentType: 'application/json; charset=utf-8',
   success: function (response) {
    //do your actions
   },
   error: function (response) {
    alert("error occured");
   }
   });
Polymyxin answered 2/3, 2017 at 13:55 Comment(0)
J
3

I can confirm that on asp.net core 2.1, removing the content type made my ajax call work.

function PostData() {
    var answer = [];

    for (let i = 0; i < @questionCount; i++) {
        answer[i] = $(`#FeedbackAnswer${i}`).dxForm("instance").option("formData");
    }

    var answerList = { answers: answer }

    $.ajax({
        type: "POST",
        url: "/FeedbackUserAnswer/SubmitForm",
        data: answerList ,
        dataType: 'json',
        error: function (xhr, status, error) { },
        success: function (response) { }
    });
}
[HttpPost]
public IActionResult SubmitForm(List<Feedback_Question> answers)
{}
Juggle answered 8/7, 2021 at 12:38 Comment(0)
E
2

Wrapping your list of objects with another object containing a property that matches the name of the parameter which is expected by the MVC controller works. The important bit being the wrapper around the object list.

$(document).ready(function () {
    var employeeList = [
        { id: 1, name: 'Bob' },
        { id: 2, name: 'John' },
        { id: 3, name: 'Tom' }
    ];      

    var Employees = {
      EmployeeList: employeeList
    }

    $.ajax({
        dataType: 'json',
        type: 'POST',
        url: '/Employees/Process',
        data: Employees,
        success: function () {          
            $('#InfoPanel').html('It worked!');
        },
        failure: function (response) {          
            $('#InfoPanel').html(response);
        }
    }); 
});


public void Process(List<Employee> EmployeeList)
{
    var emps = EmployeeList;
}

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
}
Evie answered 21/9, 2017 at 22:6 Comment(0)
D
1
     var List = @Html.Raw(Json.Encode(Model));
$.ajax({
    type: 'post',
    url: '/Controller/action',
    data:JSON.stringify({ 'item': List}),
    contentType: 'application/json; charset=utf-8',
    success: function (response) {
        //do your actions
    },
    error: function (response) {
        alert("error occured");
    }
});
Dispatch answered 4/1, 2017 at 9:32 Comment(1)
Try this code for passing List Of model objects using ajax. Model represents the IList<Model>. Use IList<Model> in controller to get the values.Dispatch
A
1

Removing contentType just worked for me in asp.net core 3.1

All other methods failed

Anastomose answered 1/7, 2021 at 14:54 Comment(0)
E
0

If you are using ASP.NET Web API then you should just pass data: JSON.stringify(things).

And your controller should look something like this:

public class PassThingsController : ApiController
{
    public HttpResponseMessage Post(List<Thing> things)
    {
        // code
    }
}
Exurbanite answered 25/12, 2015 at 10:7 Comment(0)
M
0

Modification from @veeresh i

 var data=[

                        { id: 1, color: 'yellow' },
                        { id: 2, color: 'blue' },
                        { id: 3, color: 'red' }
                        ]; //parameter
        var para={};
        para.datav=data;   //datav from View


        $.ajax({
                    traditional: true,
                    url: "/Conroller/MethodTest",
                    type: "POST",
                    contentType: "application/json; charset=utf-8",
                    data:para,
                    success: function (data) {
                        $scope.DisplayError(data.requestStatus);
                    }
                });

In MVC



public class Thing
    {
        public int id { get; set; }
        public string color { get; set; }
    }

    public JsonResult MethodTest(IEnumerable<Thing> datav)
        {
       //now  datav is having all your values
      }
Michelemichelina answered 24/4, 2017 at 7:56 Comment(0)
S
0

What I did when trying to send some data from several selected rows in DataTable to MVC action:

HTML At the beginning of a page:

@Html.AntiForgeryToken()

(just a row is shown, bind from model):

 @foreach (var item in Model.ListOrderLines)
                {
                    <tr data-orderid="@item.OrderId" data-orderlineid="@item.OrderLineId" data-iscustom="@item.IsCustom">
                        <td>@item.OrderId</td>
                        <td>@item.OrderDate</td>
                        <td>@item.RequestedDeliveryDate</td>
                        <td>@item.ProductName</td>
                        <td>@item.Ident</td>
                        <td>@item.CompanyName</td>
                        <td>@item.DepartmentName</td>
                        <td>@item.ProdAlias</td>
                        <td>@item.ProducerName</td>
                        <td>@item.ProductionInfo</td>
                    </tr>
                }

Button which starts the JavaScript function:

 <button class="btn waves-effect waves-light btn-success" onclick="ProcessMultipleRows();">Start</button>

JavaScript function:

  function ProcessMultipleRows() {
            if ($(".dataTables_scrollBody>tr.selected").length > 0) {
                var list = [];
                $(".dataTables_scrollBody>tr.selected").each(function (e) {
                    var element = $(this);
                    var orderid = element.data("orderid");
                    var iscustom = element.data("iscustom");
                    var orderlineid = element.data("orderlineid");
                    var folderPath = "";
                    var fileName = "";

                    list.push({ orderId: orderid, isCustomOrderLine: iscustom, orderLineId: orderlineid, folderPath: folderPath, fileName : fileName});
                });

                $.ajax({
                    url: '@Url.Action("StartWorkflow","OrderLines")',
                    type: "post", //<------------- this is important
                    data: { model: list }, //<------------- this is important
                    beforeSend: function (xhr) {//<--- This is important
                      xhr.setRequestHeader("RequestVerificationToken",
                      $('input:hidden[name="__RequestVerificationToken"]').val());
                      showPreloader();
                    },
                    success: function (data) {

                    },
                    error: function (XMLHttpRequest, textStatus, errorThrown) {

                    },
                     complete: function () {
                         hidePreloader();
                    }
                });
            }
        }

MVC action:

[HttpPost]
[ValidateAntiForgeryToken] //<--- This is important
public async Task<IActionResult> StartWorkflow(IEnumerable<WorkflowModel> model)

And MODEL in C#:

public class WorkflowModel
 {
        public int OrderId { get; set; }
        public int OrderLineId { get; set; }
        public bool IsCustomOrderLine { get; set; }
        public string FolderPath { get; set; }
        public string FileName { get; set; }
 }

CONCLUSION:

The reason for ERROR:

"Failed to load resource: the server responded with a status of 400 (Bad Request)"

Is attribute: [ValidateAntiForgeryToken] for the MVC action StartWorkflow

Solution in Ajax call:

  beforeSend: function (xhr) {//<--- This is important
                      xhr.setRequestHeader("RequestVerificationToken",
                      $('input:hidden[name="__RequestVerificationToken"]').val());
                    },

To send List of objects you need to form data like in example (populating list object) and:

data: { model: list },

type: "post",

Slipover answered 31/3, 2020 at 13:54 Comment(0)
S
0

Nothing worked for me in asp.net core 3.1. Tried all the above approaches. If nothing is working and someone is reading the rows from table and wanted to pass it to Action method try below approach... This will definitely work...

<script type="text/javascript">
    $(document).ready(function () {

        var data = new Array();
      var things = {};

      // make sure id and color properties match with model (Thing) properties
      things.id = 1;
      things.color = 'green';

      data.push(things);

      Try the same thing for dynamic data as well that is coming from table.

        // var things = [ { id: 1, color: 'yellow' }, { id: 2, color: 'blue' }, { id: 3, color: 'red' } ];

        $.ajax({
            contentType: 'application/json;',
            type: 'POST',
            url: 'your url goes here',
            data: JSON.stringify(things)
        });
    });
</script>

public class ThingController : Controller
{
    public void PassThing([FromBody] List<Thing> things)
    {
        // do stuff with things here...
    }

    public class Thing
    {
        public int id { get; set; }
        public string color { get; set; }
    }
}
Sebi answered 9/6, 2022 at 12:42 Comment(0)
H
0

The way that worked for me

            $.ajax({
            url: '@Url.Action("saveVideoesCheckSheet", "checkSheets")',
            type: "POST",
            contentType: "application/x-www-form-urlencoded; charset=utf-8",
            data: "data=" + JSON.stringify(videos),
            success: function (response) {
                window.location.reload(true);
            },
            failure: function (msg) {
                
            }
        });
    });

Controller

       public  string saveVideoesCheckSheet(string data)
    {

        List<editvideo> lst = JsonConvert.DeserializeObject<List<editvideo>>(data);...}

After much experimentation, bit of a cheat.

Hyperboloid answered 7/2, 2023 at 13:29 Comment(0)
V
0

Send data from the list checkbox clicked to an array and pass the list type of the model in the controller to create a new model as an array name match and declare the model property you want from the view page.

<script>
    function save() {
        alert('hi'); 
        var cartridges = new Array();
        $("#tbl1  input:checked ").each(function () {
            var row = $(this).parents("tr");
            var cartridge = {};
            cartridge.Id = row.find("TD").eq(0).html();
            cartridge.Name = row.find("TD").eq(1).html();
            cartridges.push( cartridge );
        });
        //alert(JSON.stringify(customers) + "rfgdfcd");
        $.ajax({
            type: 'post',
            url: '@Url.Action("saveDetails", "Home")',
            data: JSON.stringify(cartridges),
            dataType: "json",
            contentType: 'application/json',
            success: function (response) {
                alert("succese");
            },
                failure: function (response) {
                    alert("fail");
            },
                error: function (response) {
                    alert("error");
            },
        });
    }
</script>
Vagary answered 31/3, 2023 at 4:49 Comment(2)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Glycogen
how can we add file upload to it.Goal

© 2022 - 2024 — McMap. All rights reserved.