-1

MVC4. I have a dynamic list on a view, a new textbox is added with button click (which adds a partialView) so user can enter a list of stuff. That is contained in a form element with a submit button.

In the controller I have tried three different types:

    [HttpPost]
    public ActionResult Index(IEnumerable<AccessoryVM> form)
    {
           -- form is NULL


    [HttpPost]
    public ActionResult Index(AccessoryVM form)
    {
           -- form has only the first item in the list


    [HttpPost]
    public ActionResult Index(FormCollection form)
    {
        -- seems to receive the list, but having trouble getting the values

All the examples I have seen are using a for list to add an index to each item, but they aren't using a dynamic list (it has a fixed length).

What should the Controller receiving type be?

EDIT to add more detail:

Button click appends partial view:

$("#add-item").on("click", function () {
    $.ajax({
        url: '/Accessory/AddItem',
        cache: false,
        success: function (html) {
            $("#form-body").append(html);
        }
    })
    return false;
})

Partial View:

@model EmployeeHardwareRequest.Models.ViewModels.AccessoryVM

<div class="form-group col-md-3">
    @Html.LabelFor(model => model.ItemDescription, htmlAttributes: new { @class = "control-label" })
    <div>
        @Html.DropDownListFor(model => model.AccessoryId, Model.AccessoryDdl, new { @class = "form-control" })
    </div>
</div>

<div class="form-group col-md-9">
    @Html.LabelFor(model => model.ProductLink, htmlAttributes: new { @class = "control-label" })
    <div>
        @Html.EditorFor(model => model.ProductLink, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.ProductLink, "", new { @class = "text-danger" })
    </div>
</div>

Main View - partial is appended to the #form-body:

    @using (Html.BeginForm("Index", "Accessory", FormMethod.Post, new { @id="accessory-form", @class = "form-horizontal" }))
        {
        @Html.AntiForgeryToken()

        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

                <div id="form-body">
                    <div class="form-group col-md-3">
                        @Html.LabelFor(model => model.ItemDescription, htmlAttributes: new { @class = "control-label" })
                        <div>
                            @Html.DropDownListFor(model => model.SelectedAccessory, Model.AccessoryDdl, new { @class = "form-control" })
                        </div>
                    </div>

                    <div class="form-group col-md-9">
                        @Html.LabelFor(model => model.ProductLink, htmlAttributes: new { @class = "control-label" })
                        <div>
                            @Html.EditorFor(model => model.ProductLink, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.ProductLink, "", new { @class = "text-danger" })
                        </div>
                    </div>
                </div>

            <div class="row">
                <div class="col-md-6">
                    <button id="add-item" class="btn btn-primary">Add Another Item</button>
                </div>
                <div class="col-md-6">
                    <input type="submit" value="Select Software" class="btn btn-default pull-right" />
                </div>
            </div>
        }
BattlFrog
  • 3,370
  • 8
  • 56
  • 86
  • Take a look at [this](http://stackoverflow.com/a/34074441/40521) which has a complete working code. – Shyju Dec 21 '15 at 20:28

1 Answers1

0

Most likely, you have a binding issue. Assuming all you're posting is a collection of AccessoryVM, then the parameter should be List<AccessoryVM> form. However, in order for the modelbinder properly bind the posted values, your input names must be in a specific format, namely either form[N].Foo or just [N].Foo.

You haven't given any detail about what's going on in your view, but since these are dynamically added, you must be using JavaScript to add additional inputs to the page. If you're doing it via AJAX (returning a partial view), you'll need to pass the index to your endpoint so that it can be utilized to generate the right input names. If you're using something like Knockout, Angular, etc., you should ensure that whatever template is being used to generate the inputs takes an index into account.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • 1
    This should've been posted as a comment. – ataravati Dec 21 '15 at 20:41
  • @ataravati: Umm, no. It's an answer. It's a guess, admittedly, because the OP provided very little information to work with, but based on experience, I'm confident it's a very good guess. – Chris Pratt Dec 21 '15 at 20:46
  • One of the biggest problems on SO is people posting things like this as comments, which effectively answer the question, so the question goes unanswered forever. – Chris Pratt Dec 21 '15 at 20:47
  • A guess cannot be an answer. If the OP provides little information, you can always ask for more. Then, when you have enough information to be able to answer the question without guessing, you post an answer. – ataravati Dec 21 '15 at 21:01
  • @ataravati: Sorry, but you're incorrect. *This is an answer*. If the OP provides more information that ends up contradicting what I've said here, then I can edit it accordingly. In the meantime, based on the information provided, this details the cause and how to go about solving it. The fact that it's somewhat generalized because of limited visibility into the OP's code is meaningless. – Chris Pratt Dec 21 '15 at 21:05
  • @Chris - What is the preferred method for adding an index to the ids? I have looked around and I can figure it out if I am just adding html with the JS, but because I have to use partial views (because of the dropdowns), I can't find a way to add an index each time I add a new partial view instance to teh view. – BattlFrog Dec 22 '15 at 20:31
  • You'll either have to send the index along with the AJAX request, and then make use of `ViewData.TemplateInfo.HtmlFieldPrefix` to generate the right name, or utilize some sort of JavaScript templating library along with something that supports data-binding (Knockout, Angular, etc.) to automatically handle the indexing of the fields. – Chris Pratt Dec 28 '15 at 15:43