TZHX
TZHX

Reputation: 5377

How to have List Objects retained in the model on HttpPost?

I have a Model that contains a List of a custom type.

I want the data from this type to be passed back in when a model is submitted as a HttpPost call the the controller.

However, it does not seem to do what I want. I've got where I am so far by following Passing IEnumerable or list Model to Controller using HttpPost but I'm having a problem.

My controller method:

    [HttpPost]
    public ActionResult UpdateStock(int id, ProductModel model)
    {
        return View("UpdateStock", model);
    }

Now, the View is like this (trimmed):

@using (Html.BeginForm())
{
<div>
    <p>
    <input type="submit" value="Save" />
    </p>

    @Html.HiddenFor(m => m.ProductNo)

    <div class = "title">
    @Html.LabelFor(m => m.ProductName)
    @Html.EditorFor(m => m.ProductName)
    </div>

            @for ( int i = 0; i < Model.Stock.Count; i++ )
            {
                var item = Model.Stock[i];
                <div class="editor-field">
                    <input type="text" name="Model.Stock[@i].Key"
                        value="@item.Key" />
                </div>
                <div class="editor-field">
                    <input type="text" name="Model.Stock[@i].Value"
                        value="@item.Value" />
                </div>
            }
}

My problem is, that it seems the @Html.EditorFor() and <input type=.../> tags don't seem to play well with each other. If I have it like above, then the ProductNo and other properties using @Html methods won't be passed through to the model.

Any advice much appreciated.

Upvotes: 0

Views: 819

Answers (1)

Darin Dimitrov
Darin Dimitrov

Reputation: 1038710

I would simply use editor templates:

Model:

public class ProductModel 
{
    public string ProductNo { get; set; }
    public string ProductName { get; set; }
    public IEnumerable<Stock> Stocks { get; set; }
}

public class Stock
{
    public string Key { get; set; }
    public string Value { get; set; }
}

Controller:

public class HomeController: Controller
{
    public ActionResult Index()
    {
        var model = new ProductModel 
        {
            ProductNo = "123",
            ProductName = "p name",
            Stocks = new[]
            {
                new Stock { Key = "key1", Value = "value1" },
                new Stock { Key = "key2", Value = "value2" },
            }
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(ProductModel model)
    {
        ...
    }
}

View:

@model ProductModel
@using (Html.BeginForm())
{
    <p>
        <input type="submit" value="Save" />
    </p>

    @Html.HiddenFor(m => m.ProductNo)

    <div class = "title">
        @Html.LabelFor(m => m.ProductName)
        @Html.EditorFor(m => m.ProductName)
    </div>

    @Html.EditorFor(x => x.Stocks)
}

and then you define a custom editor template for the Stock type (~/Views/Shared/EditorTemplates/Stock.cshtml):

@model Stock
<div class="editor-field">
    @Html.EditorFor(x => x.Key)
</div>
<div class="editor-field">
    @Html.EditorFor(x => x.Value)
</div>

Upvotes: 2

Related Questions