asp.net-coreasp.net-core-mvcjsonresult

Model binding with multiple rows in ASP.NET Core MVC


I've been stuck on this for so long, any help or direction is appreciated.

Basically I want my controller to pass a json data like this:

Sample data I would like to pass to my API

Initially, I wanted to do it with model binding, but at this moment even jQuery will be fine.

Model class:

public class Orders
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
    public string ItemName { get; set; }
    public double Price { get; set; }

    public IEnumerable<SelectListItem> CustomersList { get; set; }
}

Controller code:

// GET: OrdersController/Create
public ActionResult Create()
{
   var listCustomers = dbContext.Customers
       .Select(x => new SelectListItem
       {
           Value = x.Id.ToString(),
           Text = x.DepName
       });

        var orders = new Orders()
        {
            CustomersList = listCustomers
        };

    //var orders = new List<Orders>();
    return View(orders);
}

// POST: OrdersController/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(List<Orders> ordersList)
{
    Orders newOrders = new Orders();

    foreach (var order in ordersList)
    {
        newOrders.Id = 0;
        newOrders.CustomerId = order.CustomerId;
        newOrders.ItemName = order.ItemName;
        newOrders.Price = order.Price;
    }

    // I will be processing newOrders into application/json and sending to the backend API
}

View markup:

@model List<NameSpace.Web.Models.Orders>

@{
  ViewData["Title"] = "Create";
  Layout = "~/Views/Shared/_Layout.cshtml";
}

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

<div class="row">

    <div class="col-md-8">
       <div class="form-group">
           @Html.LabelFor(model => model.CustomerId, htmlAttributes: new { @class = "control-label col-md-6" })
           @Html.DropDownListFor(model => model.CustomerId, Model.CustomersList, "Select Customer ", new { @class = "form-control" })
           @Html.ValidationMessageFor(model => model.DepId, "", new { @class = "text-danger" })
       </div>
    </div>

    <hr>

    <div class="col-md-12">
        <div class=''></div>
       
            <thead>
                <tr>
                    //<th style="width:150px">Cust. Id</th>
                    <th style="width:150px">Item Name</th>
                    <th style="width:150px">Price</th>
                </tr>
            </thead>

            <tbody id="tblOrdersBody">
                <tr>
                    //<td><input name='Orders[0].CustomerId' class="form-control" /></td>
                    <td><input name='Orders[0].ItemName' class="form-control" /></td>
                    <td><input name='Orders[0].Price' class="form-control" /></td>
                </tr>
            </tbody>
            <tfooter>
                <tr><a hre="#" class="btn btn-success" id="addOrder"></a> </tr>
            </tfooter>
        </table>


        <div class="row">
            <div class="tile-footer d-flex justify-content-around">
                @Html.ActionLink("Cancel", "Index", null, new { @class = "btn btn-danger" })
                <input id="btnSave" type="submit" value="Save Order" class="btn btn-primary" />
            </div>
        </div>
    </div>
</div>
}

@section Scripts {

<script>
    var i = 1;
    $(document).on("click", "#addOrder", function () {

        $("#tblOrdersBody").append("<tr>"
            //+ "<td><input name='Orders[" + i + "].CustomerId' class='form-control' /></td>"
            + "<td><input name='Orders[" + i + "].ItemName' class='form-control'/></td>"
            + "<td><input name='Orders[" + i + "].Price' class='form-control'/></td>"
            + "<td><button type='button' class='btn btn-danger' id='btnRemove' </buuton></td>"
            + "</tr > ");
        i++;
    });
</script>
}

I have seen many similar questions , the closest one being this one, but I could figure it out, the controller receives 0 in item counts


Solution

  • public ActionResult Create(List ordersList)

    You action parameter named ordersList, please try to modify the name attribute of your input(s) on view page, like below.

    <tbody id="tblOrdersBody">
        <tr>
            <td><input name='ordersList[0].CustomerId' class="form-control" /></td>
            <td><input name='ordersList[0].ItemName' class="form-control" /></td>
            <td><input name='ordersList[0].Price' class="form-control" /></td>
        </tr>
    </tbody>
    

    JS code

    <script>
        var i = 1;
        $(document).on("click", "#addOrder", function () {
    
            $("#tblOrdersBody").append("<tr>"
                + "<td><input name='ordersList[" + i + "].CustomerId' class='form-control' /></td>"
                + "<td><input name='ordersList[" + i + "].ItemName' class='form-control'/></td>"
                + "<td><input name='ordersList[" + i + "].Price' class='form-control'/></td>"
                + "<td><button type='button' class='btn btn-danger' id='btnRemove' </buuton></td>"
                + "</tr > ");
            i++;
        });
    </script>
    

    Test Result

    enter image description here