Home > front end >  Dynamically added form data not binding on postback .net framework 4.7.2 MCV using EF
Dynamically added form data not binding on postback .net framework 4.7.2 MCV using EF

Time:03-07

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 >
        <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"  />
                    </td>
                    <td>
                        <input asp-for="@Model.AllDates[i].EndDateTime"  />
                    </td>
                    <td>
                        <button type="button" >
                            <i ></i>
                        </button>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    <div>
        <button type="button"  id="addDateTime">Add Shift</button>
    </div>
    <div>
        <input type="submit"  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.

CodePudding user response:

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)">

CodePudding user response:

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

Not only your postback. You even cannot receive the model in backend which caused postback null model.

Model Binding system binds the property by name attribute. Your frontend name attribute is like testMainModel.AllDates[index].PropertyName, which does not match the backend.

A simple way is to change your post action parameter name like below:

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

    var x = testMainModel;

    var y = 1;

    return View(testMainModel);
}

Another way is that you can change the name from testMainModel.AllDates[index].PropertyName to AllDates[index].PropertyName. In this way you will no need change the action parameter.

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', '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', 'AllDates['   countVal   '].EndDateTime').addClass('form-control');

BTW, ASP.NET does not have tag helper, it uses Html Helper. Tag Helper exists in ASP.NET Core.

  • Related