Search code examples
javascriptc#asp.netasp.net-mvcasp.net-mvc-5

ASP.NET MVC - Controller receives the list incorret from view using Html.BeginForm()


I want to get multiple instances of my model objects sent to the controller as a list but for some reason, the count of the list is always 1 and the value of the object is always 0 so nothing is actually posted when submit is pressed.

This is my View:

@model List<MVCModel.Models.Student>

 <b>Items</b>    @ViewBag.Items <br />
 <b>Value</b>    @ViewBag.Value <br />
  
@using (Html.BeginForm("Form", "Home", FormMethod.Post))
{
<table>
    <tbody id="GenaratorList">
        <tr>
          @{
            int counter = 0;
            <td>Enter Name: </td>
            <td>@Html.TextBoxFor(m => m[counter].Name, new {id = "Name"})</td>
            <td>Enter Age: </td>
            <td>@Html.TextBoxFor(m => m[counter].Age, new {id = "Age"})</td>
            <td><input type="button" value="Add" onclick="addGenarator()" /></td>
        </tr>
        counter++;
        }
     <tbody>
</table>
<input type="submit" value="Submit Form"/>
}

<script>
    count = 0;
    function addGenarator() {
        var Name = $('#Name').val();
        var Age = $('#Age').val();
        var Student = "studentModels[" + count + "]";
        $('#GenaratorList').append('<tr><td><input id="' + Student + '.Name" Name="' + Student + '.Name" type="text" class="form-control" readonly value="' + Name + '"></td><td><input id="' + Student + '.Age" Age="' + Student + '.Age" type="text" class="form-control" readonly value="' + Age + '"></td></tr>');
        $('#Name,#Age').val('');
        count++;
    }
</script>

This is my Controller:

[HttpPost]
public ActionResult Form(List<Student> s)
{
    ViewBag.Items = s.Count; // ALWAYS RETURNS 1
    ViewBad.Value = s[0].Age // TEST VALUE OF FIRST ITEM RETURNS 0
    return View("Index");
}

This is my model:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MVCModel.Models
{
    public class Student
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
}

Solution

  • Your Form (HttpPost) API was expected to receive a request body with an array named s. You will pass the array as (name) studentModels based on your JS code.

    var Student = "studentModels[" + count + "]";
    

    And you miss out on the name attribute for each Age input.

    <input id="' + Student + '.Age" Age="' + Student + '.Age" type="text" class="form-control" readonly value="' + Age + '">
    

    To fix, make sure the array name in View must be matched with the Controller parameter name. For the below code, I name the array as s which is the same as the Controller API expected parameter name.

    Also, apply with template literals and string interpolation to make the HTML string looks clean and easier to bind the values with variables.

    function addGenarator() {
        var Name = $('#Name').val();
        var Age = $('#Age').val();
        var Student = "s[" + count + "]";
    
        var html = `
            <tr>
                <td><input id="${Student}.Name" name="${Student}.Name" type="text" class="form-control" readonly value="${Name}" /></td>
                <td><input id="${Student}.Age" name="${Student}.Age" type="text" class="form-control" readonly value="${Age}" /></td>
            </tr>
        `;
        $('#GenaratorList').append(html);
        $('#Name,#Age').val('');
        count++;
    }
    

    Submitted form & Request Form

    enter image description here

    Debugging Output

    enter image description here