Search code examples
.netrazorasp.net-core-mvc

Binding dynamically generated form inputs to viewModel


so I have been developing a web application with .NET 6. I have a form, which has a button that allows generating as many input rows as user wants. I tried to bind it with view model.

@model IEnumerable<AddToMealViewModel>

<button class="btn btn-success" onclick="addMore()">Add more</button>
<form method="post">
    <div class="wrapper">
        <div class="row-fluid">
            <div>
                @Html.DropDownListFor(m => m.SelectedMealId,
                         new SelectList(Model.Meals, "Id", "Name"),
                         "Select")
                @Html.DropDownListFor(m => m.SelectedProductId,
                         new SelectList(Model.Products, "Id", "Name"),
                         "Select")
                <input asp-for="@Model.Amount" />
            </div>
        </div>
    </div>
    <button type="submit" class="btn btn-primary">Add</button>
</form>
<script>
    function addMore() {
        $(".row-fluid:last").clone().appendTo(".wrapper");
    }
</script>

The thing is, I have no idea how to automatically bind the newly generated fields to the ViewModel to pass to my Controller.


Solution

  • To dynamically generate input rows and bind them to your view model, you can try these steps:

    In Razor view

    @model IEnumerable<AddToMealViewModel>
    
    <button class="btn btn-success" onclick="addMore()">Add more</button>
    <form method="post">
        <div class="wrapper">
            @for (var i = 0; i < Model.Count(); i++)
            {
                <div class="row-fluid">
                    <div>
                        @Html.DropDownListFor(m => Model.ElementAt(i).SelectedMealId, new SelectList(Model.ElementAt(i).Meals, "Value", "Text"), "Select")
                        @Html.DropDownListFor(m => Model.ElementAt(i).SelectedProductId, new SelectList(Model.ElementAt(i).Products, "Value", "Text"), "Select")
                        <input asp-for="Model.ElementAt(i).Amount" />
                    </div>
                </div>
            }
        </div>
        <button type="submit" class="btn btn-primary">Add</button>
    </form>
    <script>
        var index = @Model.Count();
        function addMore() {
            var newRow = $(".row-fluid:last").clone();
            newRow.find(':input').val(''); // Clear input values
            newRow.find('select').prop('selectedIndex', 0); // Reset dropdowns
            newRow.find(':input').each(function () {
                var name = $(this).attr('name').replace(`[${index - 1}]`, `[${index}]`);
                $(this).attr('name', name);
            });
            newRow.appendTo(".wrapper");
            index++;
        }
    </script>
    

    In controller

    [HttpPost]
    public IActionResult YourAction(IFormCollection form)
    {
        // var dynamicColumn1= form["dynamicColumn1"];
        // etc.
    }