Dynamic amount of DateTime controls forwarded to controller

Viewed 21

I've created a model that has its own class:

public class VMRequest()
{
    public int Id { get; set; }

    public List<Slot> Slots { get; set; }

    public class Slot()
    {
        public DateTime Date { get; set; }
    }
}

Then let's say I add five Slots to the list, they show perfectly in a View if I do it like this:

<form asp-action="Request">
<div class="row flex-column">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        @foreach (var slot in Model.Slots)
        {
            <div class="col-md-6">
                <div class="form-group">
                    <label asp-for="@slot.Date" class="control-label"></label>
                    <input asp-for="@slot.Date" type="date" class="form-control" />
                    <span asp-validation-for="@slot.Date" class="text-danger"></span>
                </div>
            </div>              
        }
        <div class="form-group">
            <input type="submit" value="Create" class="btn btn-primary" />
        </div>
    </div>
</form>

But then on submission, even though the VMRequest model is passed to the controller, the changes on the view controls don't pass - I have no idea how to pin identifiers to each of the controls??

I'm sure this is possible!?

2 Answers

Change your code to:

    @for(int x = 0; x < Model.Slots.Length;x++)
    {
        <div class="col-md-6">
            <div class="form-group">
                <label asp-for="@Model.Slots[x].Date" class="control-label"></label>
                <input asp-for="@Model.Slots[x].Date" type="date" class="form-control" />
                <span asp-validation-for="@Model.Slots[x].Date" class="text-danger"></span>
            </div>
        </div>              
    }

Then the form posted back will be correct.

Each element needs to be named with an index to bind back to the model. There is a great example at https://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/.

In Short: Using a razor component within a for loop should handle this for you like:

for (int i = 0; i < 3; i++)
  @Html.TextBoxFor(m => m[i].Title)
  @Html.TextBoxFor(m => m[i].Author)
  @Html.TextBoxFor(m => m[i].DatePublished)
}
Related