简体   繁体   中英

Model not being passed in post method which should update entities from changed form input values

My model contains two lists of the Order entity type, but differentiating only by the value of the Status property. When Orders are created, the status property is automatically set to In Progress and in the AdminOrders view , placed in the Orders In Progress table . The AdminOrders view has two tables: Orders In Progress table and Orders Dispatched table which will be filled by the Model 's lists respectively.

When the Status value of new orders is changed from the drop down list to dispatched , and when the update button in the view is clicked, the post request should be triggered - passing the model to it. However when I debug the AdminOrders post method, the model parameter is null.

Here's the Model class:

public class AdminOrdersViewModel
{
    public List<Order> OrdersInProgress { get; set; }
    public List<Order> OrdersDespatched { get; set; }
}

These are the controller actions:

[HttpGet]
[Authorize(Roles = "Admin")]
public ActionResult AdminOrders()
{
    var model = db.Orders.Where(o => o.Status == "In Progress").ToList();
    var model2 = db.Orders.Where(o => o.Status == "Despatched").ToList();

    return View(new AdminOrdersViewModel { OrdersInProgress = model, OrdersDespatched = model2 });
}

[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<ActionResult> AdminOrders([Bind(Include = "OrdersInProgress, OrdersDespatched")] AdminOrdersViewModel model)
{
    if (ModelState.IsValid)
    {
        foreach (var item in model.OrdersDespatched)
        {
            db.Entry(item).State = EntityState.Modified;
        }

        foreach (var item2 in model.OrdersInProgress)
        {
            db.Entry(item2).State = EntityState.Modified;
        }

        await db.SaveChangesAsync();

        var ordersInProgress = db.Orders.Where(o => o.Status == "In Progress").ToList();
        var ordersDespatched = db.Orders.Where(o => o.Status == "Despatched").ToList();

        return View(new AdminOrdersViewModel { OrdersDespatched = ordersDespatched, OrdersInProgress = ordersInProgress });
    }

    return View(model);
}

In the Get request AdminOrders method, each Model list's entity is updated and a new Model is given to the View when the View is returned, so the page should update and Orders moved to the correct table depending on the status property. However the model is left null.

The form in the View assigns the View's Model to the Post method model parameter:

@using (Html.BeginForm("AdminOrders", "Manage", new { model = Model }, FormMethod.Post, new
    {
        enctype = "multipart/form-data"
    }))
    {
   }

I have also tried to pass in two new lists in the Post method with the Model's lists individually assigned in the form request, but receive errors. How do I ensure the Post request passes the updated model to the AdminOrders post method?

The full View Page code is the following:

@model ValueVille.Models.AdminOrdersViewModel

@{
    ViewBag.Title = "Orders";

}

<div class="main-content-container">

    <h1>New Orders In Progress</h1>
@using (Html.BeginForm("AdminOrders", "Manage", new { model = Model }, FormMethod.Post, new
{
    enctype = "multipart/form-data"
}))
{
        @Html.AntiForgeryToken()

        <table class="panel panel-default table cart-table">
            <tr>
                <th>
                    Order ID
                </th>
                <th>
                    Total
                </th>
                <th>
                    Date
                </th>
                <th>
                    Status
                </th>
            </tr>
            @foreach (var item in Model.OrdersInProgress)
            {
                <tr>
                    <td>
                        <a href="@Url.Action("OrderDetails", "Home", new { id = item.OrderId })">
                            @item.OrderId
                        </a>
                    </td>
                    <td>
                        £@item.Total
                    </td>
                    <td>
                        @item.OrderDate
                    </td>
                    <td>
                        @{
                            List<SelectListItem> listItems = new List<SelectListItem>();
                            listItems.Add(new SelectListItem
                            {
                                Text = item.Status,
                                Value = "Option1"
                            });
                            listItems.Add(new SelectListItem
                            {
                                Text = "Despatched",
                                Value = "Option2",

                            });

                        }

                        @Html.DropDownListFor(m => item.Status, listItems, item.Status)
                    </td>
                </tr>
                            }

        </table>

        <h1>Orders Despatched</h1>

        <table class="panel panel-default table cart-table">
            <tr>
                <th>
                    Order ID
                </th>
                <th>
                    Total
                </th>
                <th>
                    Date
                </th>
                <th>
                    Status
                </th>
            </tr>
            @foreach (var item in Model.OrdersDespatched)
            {
                <tr>
                    <td>
                        <a href="@Url.Action("OrderDetails", "Home", new { id = item.OrderId })">
                            @item.OrderId
                        </a>
                    </td>
                    <td>
                        £@item.Total
                    </td>
                    <td>
                        @item.OrderDate
                    </td>
                    <td>
                        @{
                            List<SelectListItem> listItems = new List<SelectListItem>();
                            listItems.Add(new SelectListItem
                            {
                                Text = item.Status,
                                Value = "Option1"
                            });
                            listItems.Add(new SelectListItem
                            {
                                Text = "Despatched",
                                Value = "Option2",

                            });

                        }

                        @Html.DropDownListFor(m => item.Status, listItems)
                    </td>
                </tr>
                            }

        </table>

        <div class="panel-body form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Update" class="btn btn-success" />
            </div>
        </div>

                            }



</div>

Modify your ViewModel to:

public class AdminOrdersViewModel
{
    public List<Order> OrdersInProgress { get; set; }
    public List<Order> OrdersDespatched { get; set; }
    public List<Status> OrderStatuses { get; set; }
}

Your view should look now like:

@model ValueVille.Models.AdminOrdersViewModel
@{
    ViewBag.Title = "Orders";
}

<div class="main-content-container">
    <h1>New Orders In Progress</h1>
    @using (Html.BeginForm("AdminOrders", "Manage", FormMethod.Post, new { enctype = "multipart/form-data" }))
    {
        @Html.AntiForgeryToken()

        <table class="panel panel-default table cart-table">
            <thead>
                <tr>
                    <th>Order ID</th>
                    <th>Total</th>
                    <th>Date</th>
                    <th>Status</th>
                </tr>
            </thead>
            <tbody>
                @for (int i = 0; i < Model.OrdersInProgress.Count(); i++)
                {
                    <tr>
                        <td>
                            <a href="@Url.Action("OrderDetails", "Home", new { id = Model.OrdersInProgress[i].OrderId })">@Model.OrdersInProgress[i].OrderId</a>
                            @Html.HiddenFor(x => x.Model.OrdersInProgress[i].OrderId)
                        </td>
                        <td>
                            £@Model.OrdersInProgress[i].Total
                            @Html.HiddenFor(x => x.Model.OrdersInProgress[i].Total)
                        </td>
                        <td>
                            @Model.OrdersInProgress[i].OrderDate
                            @Html.HiddenFor(x => x.Model.OrdersInProgress[i].OrderDate)
                        </td>
                        <td>
                            @Html.DropDownListFor(m => Model.OrdersInProgress[i].Status, new SelectList(Model.OrderStatuses, "Id", "StatusName"))
                        </td>
                    </tr>
                }
            </tbody>
        </table>

        <h1>Orders Despatched</h1>
        <table class="panel panel-default table cart-table">
            <thead>
                <tr>
                    <th>Order ID</th>
                    <th>Total</th>
                    <th>Date</th>
                    <th>Status</th>
                </tr>
            </thead>
            <tbody>
                @for (int i = 0; i < Model.OrdersDespatched.Count(); i++)
                {
                    <tr>
                        <td>
                            <a href="@Url.Action("OrderDetails", "Home", new { id = Model.OrdersDespatched[i].OrderId })">@Model.OrdersDespatched[i].OrderId</a>
                            @Html.HiddenFor(x => x.Model.OrdersDespatched[i].OrderId)
                        </td>
                        <td>
                            £@Model.OrdersDespatched[i].Total
                            @Html.HiddenFor(x => x.Model.OrdersDespatched[i].Total)
                        </td>
                        <td>
                            @Model.OrdersDespatched[i].OrderDate
                            @Html.HiddenFor(x => x.Model.OrdersDespatched[i].OrderDate)
                        </td>
                        <td>
                            @Html.DropDownListFor(m => Model.OrdersDespatched[i].Status, new SelectList(Model.OrderStatuses, "Id", "StatusName"))
                        </td>
                    </tr>
                }
            </tbody>
        </table>

        <div class="panel-body form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Update" class="btn btn-success" />
            </div>
        </div>
    }
</div>

The controller method should look like:

[HttpPost]
public async Task<ActionResult> AdminOrders(AdminOrdersViewModel model)
{
    // do stuff
}

Assuming your Status model is somethig like:

public class Status
{
    public int Id { get; set; }
    public string StatusName { get; set; }
}

You can create the dropdownlist from your above list:

@Html.DropDownListFor(m => Model.OrdersDespatched[i].Status, new SelectList(Model.OrderStatuses, "Id", "StatusName"))

PS: Also make sure your assign a list of statuses in the Get method.

Okay, I see what you're doing...

For some reason, in asp.net MVC is seems like this should work:

@using (Html.BeginForm("AdminOrders", "Manage", new { model = Model }, FormMethod.Post, new
{
    enctype = "multipart/form-data"
}))
{
//Form contents
}

I'm passing the model right? Well, I guess not, because it doesn't work.

What you have to do is something like this (add two hidden fields to the form):

@using (Html.BeginForm("AdminOrders", "Manage", new { model = Model }, FormMethod.Post, new
{
    enctype = "multipart/form-data"
}))
{
    @Html.HiddenFor(x => x.OrdersInProgress)
    @Html.HiddenFor(x => x.OrdersDespatched)
}

And then set it up to take the two lists in the controller action.

I've had this issue when trying to pass complex objects (pocos or whatever) to the controller and found that you have to include the objects exactly as they are named and it must match what the controller expects. So if you have a List<Order> called OrdersInProgress then you have to pass a list of that type with that exact name to the controller that accepts a list of that type with that exact name. The hidden for control inside the form should pass that list with that name. If that list turns up empty check that it's name is correct.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM