'Dynamically added form data not binding on postback .net framework 4.7.2 MCV using EF

I have a model that has an array of a dynamic object. This object simply has a startdatetime, enddatetime and an int for number of slots.

I am using MVC, EF and .net 4.7.2

What I ultimately want to do is allow the user (using js) to add multiple records into a table. This works!

What is broken is on postback, the array is not binding to the array.

What am I doing wrong?

I have 2 models:

  public class testmodel
    {
     

        [Required]
        public DateTime StartDateTime { get; set; }

        [Required]
        public DateTime EndDateTime { get; set; }

        public int? NumberOfSlots { get; set; }
    }

  public class testMainModel
    {
        public List<testmodel> AllDates { get; set; }
    }

Controller:

 public async Task<ActionResult> TestShifts()
        {
            Models.testMainModel model = new Models.testMainModel();

            List<Models.testmodel> testDates = new List<Models.testmodel>();

            model.AllDates = testDates;

            return View(model) ;
        }

        [HttpPost]
        public async Task<ActionResult> TestShifts(Models.testMainModel model)
        {

            var x = model;

            var y = 1;

            return View(model);
        }

View:

@model WCSOReserves.Models.testMainModel
@{
    ViewBag.Title = "TestShifts";
}

<h2>TestShifts</h2>

@using (Html.BeginForm("TestShifts", "Events", FormMethod.Post))
{
<div>
    <table class="table table-striped">
        <thead>
            <tr>
                <th>Start Date/Time</th>
                <th>End Date/Time</th>
                <th></th>
            </tr>
        </thead>
        <tbody id="eventDateTimes" data-event-dates-start-count="@(Model.AllDates.Count - 1)">
            @for (int i = 0; i < Model.AllDates.Count; i++)
            {
                <tr data-id="@i">
                    <td>
                        <input asp-for="@Model.AllDates[i].StartDateTime" class="form-control" />
                    </td>
                    <td>
                        <input asp-for="@Model.AllDates[i].EndDateTime" class="form-control" />
                    </td>
                    <td>
                        <button type="button" class="btn btn-sm btn-danger">
                            <i class="align-middle me-2 fas fa-fw fa-trash-alt"></i>
                        </button>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    <div>
        <button type="button" class="btn btn-secondary" id="addDateTime">Add Shift</button>
    </div>
    <div>
        <input type="submit" class="btn btn-primary" id="Submit" value="Submit" />
    </div>
</div>
}
@section Scripts{
<script>
    $(document).ready(function () {
   
   
    $('button#addDateTime').on('click', function() {
        var countVal = parseInt($('#eventDateTimes').attr('data-event-dates-start-count'));
       
        countVal += 1;

        var inputStartDate = $('<input />').attr('type', 'datetime-local').attr('data-val', 'true')
            .attr('data-val-required', 'The Start Date Field is required.')
            .attr('id', 'testMainModel_AllDates_' + countVal + '__StartDateTime')
            .attr('name', 'testMainModel.AllDates[' + countVal + '].StartDateTime').addClass('form-control');

        var inputEndDate = $('<input />').attr('type', 'datetime-local').attr('data-val', 'true')
            .attr('data-val-required', 'The End Date Field is required.')
            .attr('id', 'testMainModel_AllDates_' + countVal + '__EndDateTime')
            .attr('name', 'testMainModel.AllDates[' + countVal + '].EndDateTime').addClass('form-control');

        var button = $('<button />').attr('type', 'button').addClass('btn btn-sm btn-danger')
            .append($('<i />').addClass('align-middle me-2 fas fa-fw fa-trash-alt'));

        var row = $('<tr />')
            .attr('data-id', countVal)
            .append($('<td />').append(inputStartDate))
            .append($('<td />').append(inputEndDate))
            .append($('<td />').append(button));

        $('#eventDateTimes').append(row);
       
        $('#eventDateTimes').attr('data-event-dates-start-count', countVal);
    });
   
    $(document).on('click',
        '#eventDateTimes tr td button',
        function() {
            $('tr[data-id="' + $(this).parent().parent().attr('data-id') + '"]').remove();
        });

   
});



</script>

js works, I can add rows dynamically. However, on postback, the model is empty.



Solution 1:[1]

Here data-event-dates-start-count should be same as total count.

Try

<tbody id="eventDateTimes" data-event-dates-start-count="@(Model.AllDates.Count)">

Instead of

<tbody id="eventDateTimes" data-event-dates-start-count="@(Model.AllDates.Count - 1)">

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Amit