Search code examples
c#asp.netasp.net-corecontrollerasp.net-mvc-viewmodel

Send Viewmodel with list to controller


I'm trying to submit my viewmodel with complex types, to my controller, but my viewmodel is null when it hits the controller.

Formdata in request in Network tab(chrome)

Here is the relevant code from my view:

@model ShoppingCartViewModel

@{
    ViewData["Title"] = "Indkøbskurv";
}

<h2>Indkøbskurv</h2>
<form method="post" asp-controller="ShoppingCart" asp-action="SaveProductsHistory">

    <div class="row" style="margin-bottom:30px">
        <div class="col-md-9"></div>
        <div class="col-md-3">
            <button type="submit" id="saveAndDeleteShoppingCart" class="btn btn-warning">Gem og slet kurv  <i class="fas fa-shopping-cart"></i></button>
        </div>
    </div>
    <table class="table">
        <thead>
            <tr>
                <th>Produktnavn</th>
                <th>Varenummer</th>
                <th>Antal</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @for (int i = 0; i < Model.Products.Count(); i++)
            {               
                <tr>
                    <td>
                        <div class="form-group">
                            <input type="text" asp-for="Products[i].Product.id" />
                            <input type="text" asp-for="Products[i].Product.area" />
                            <input type="text" asp-for="Products[i].Product.eurofinsItemNumber" />
                            <input type="text" asp-for="Products[i].Product.internetAddress" />
                            <input type="text" asp-for="Products[i].Product.ourResponsibility" />
                            <input type="text" asp-for="Products[i].Product.productNameEnvAir" />
                            <input type="text" asp-for="Products[i].Product.productNameSupplier" />
                            <input type="text" asp-for="Products[i].Product.storageSize" />
                            <input type="text" asp-for="Products[i].Product.storageType" />
                            <input type="text" asp-for="Products[i].Product.supplierName" />
                            <input type="text" asp-for="Products[i].Product.supplierProductNumber" />
                            <input type="text" asp-for="Products[i].Product.supplierProductNumberInfo" />
                            <input type="text" asp-for="Products[i].Product.unit" />
                            <input type="text" asp-for="Products[i].Quantity" />
                        </div>
                    </td>
                    <td>
                    </td>
                    <td>
                        <a class="adjust-button dec" aria-label="Decrease quantity" href="#">-</a>
                        <input class="adjust-input" value="@Model.Products[i].Quantity">
                        <input id="productID" type="hidden" value="@Model.Products[i].Product.id" />
                        <a class="adjust-button inc" aria-label="Increase quantity" href="#">+</a>
                    </td>
                    <td>
                        <button id="removeProductFromCookies"><i class="far fa-trash-alt"></i></button>
                    </td>
                </tr>
            }
        </tbody>
    </table>
</form>

along with my action on my controller:

 [HttpPost]
 public void SaveProductsHistory(ShoppingCartViewModel shoppingCartViewModels)
        {}

and my viewmodel

public class ShoppingCartViewModel
    {
        public List<ShoppingCartViewModelItem> Products;

        public ShoppingCartViewModel()
        {
            Products = new List<ShoppingCartViewModelItem>();
        }
    }

My view displays the data from my viewmodel just fine, and it seems like everything is sent over correctly, from inspecting the first picture in this post, but I still receive null when it hits my controller.


Solution

  • You need to expose Products as a property not field in your ShoppingCartViewModel class, that is making the object null as model binder need public setter to fill the model back at post.

    Change:

    public List<ShoppingCartViewModelItem> Products;
    

    to:

    public List<ShoppingCartViewModelItem> Products { get; set; }
    

    Edit:

    Another thing i am not sure if asp-for="Products[i].Product.id" works or not, but normally it is provided like asp-for="Model.Products[i].Product.id"

    Hope it helps.