0

This is an ASP.NET MVC project. I have a view that displays a collection of BookRentViewModel items.

When I click on the button in the view, the view is posted to an action method called rent. rent action method has a parameter called items of type IEnumerable<BookRentViewModel>.

Here is the code of the view:

@model IEnumerable<DaramSerl.Models.ViewModels.BookRentViewModel>
@using (Html.BeginForm("rent", "RentBook", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
    <table class="table">
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.bookName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.isRented)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.startDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.endDate)
            </th>
        </tr>

        @foreach (var item in Model)
        {
            <tr>
                <td>
                    @Html.EditorFor(modelItem => item.bookName)
                </td>
                <td>
                    @Html.EditorFor(modelItem => item.isRented)
                </td>
                <td>
                    @Html.EditorFor(modelItem => item.startDate)
                </td>
                <td>
                    @Html.EditorFor(modelItem => item.endDate)
                </td>
            </tr>
        }

    </table>

    <input type="submit" value="Create" class="btn btn-primary" />
}

And here is the action method:

[HttpPost]
public async Task<ActionResult> rent(IEnumerable<BookRentViewModel> items)
{
    if (ModelState.IsValid)
    {
        return RedirectToAction("/Index");
    }
    return View();
}

And here is the BookRentViewModel:

public class BookRentViewModel
{
    [Key]
    public int bookId{ get; set; }
    public string bookName { get; set; }
    public bool isRented { get; set; }
    public DateTime startDate { get; set; }
    public DateTime endDate { get; set; }
}       

The problem is that items parameter is always null when rent action is triggered.

Any idea why items is null and does not get the collection from the view?

UPDATE I used fiddler to see if the collection is posted to the server but it seems it cannot be parsed into BookRentViewModel items.

UPDATE3 Here is screenshot from fiddler with the collection sent from the view: enter image description here

Jon Schneider
  • 25,758
  • 23
  • 142
  • 170
Michael
  • 13,950
  • 57
  • 145
  • 288
  • Possible duplicate: https://stackoverflow.com/questions/10984040/post-parameter-is-always-null – Matt Evans Mar 20 '19 at 11:18
  • Why do you want all of the data being submitted? What does the form **do**? – mjwills Mar 20 '19 at 11:40
  • 1
    The updated data from fiddler looks ok, but it would be much easier to see the problem if you posted the raw request body - which you can get from your browsers network tab in dev tools. – Steve Land Mar 20 '19 at 11:46
  • 1
    I'm betting this is your problem. https://stackoverflow.com/a/17037925/7840778 – Steve Land Mar 20 '19 at 11:50
  • @SteveLand thanks it worked!!! – Michael Mar 20 '19 at 12:15
  • Possible duplicate of [How to pass IEnumerable list to controller in MVC including checkbox state?](https://stackoverflow.com/questions/17037858/how-to-pass-ienumerable-list-to-controller-in-mvc-including-checkbox-state) – mjwills Mar 20 '19 at 20:46

2 Answers2

1

Doesnt look like you're setting a value for public int bookId - if thats the case this will fail validation as its a non-nullable type.

Either way, set a breakpoint in your controller method and check the errors on ModelState - see Get error message if ModelState.IsValid fails?

Edit

To include properties but not show them on your view, use the hidden field razor tag helper: @Html.HiddenFor(x => x.bookId)

Steve Land
  • 4,852
  • 2
  • 17
  • 36
1

I tried reproduce source code.

You can change model mapping in cshtml file as below

@for (int i = 0; i < Model.Count();i++ )
        { 
            <tr>
                <td>@Html.TextBox("items[" + @i + "].bookName", 
                        Model.ElementAt(i).bookName 
                        )</td>
                <td>@Html.CheckBox("items[" + @i + "].isRented",
                        Model.ElementAt(i).isRented
                        )</td>
                <td>@Html.TextBox("items[" + @i + "].startDate",
                        Model.ElementAt(i).startDate
                        )</td>
                <td>@Html.TextBox("items[" + @i + "].endDate",
                        Model.ElementAt(i).endDate
                        )</td>

            </tr>
        }

rent.cshtml file

@model IEnumerable<WebApplication2.Controllers.BookRentViewModel>
@using (Html.BeginForm("rent", "Rent", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
    <table class="table">
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.bookName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.isRented)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.startDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.endDate)
            </th>
        </tr>

        @*@foreach (var item in Model)
        {
            <tr>
                <td>
                    @Html.EditorFor(modelItem => item.bookName)
                </td>
                <td>
                    @Html.EditorFor(modelItem => item.isRented)
                </td>
                <td>
                    @Html.EditorFor(modelItem => item.startDate)
                </td>
                <td>
                    @Html.EditorFor(modelItem => item.endDate)
                </td>
            </tr>
        }*@

        @for (int i = 0; i < Model.Count();i++ )
        { 
            <tr>
                <td>@Html.TextBox("items[" + @i + "].bookName", 
                        Model.ElementAt(i).bookName 
                        )</td>
                <td>@Html.CheckBox("items[" + @i + "].isRented",
                        Model.ElementAt(i).isRented
                        )</td>
                <td>@Html.TextBox("items[" + @i + "].startDate",
                        Model.ElementAt(i).startDate
                        )</td>
                <td>@Html.TextBox("items[" + @i + "].endDate",
                        Model.ElementAt(i).endDate
                        )</td>

            </tr>
        }

    </table>

    <input type="submit" value="Create" class="btn btn-primary" />
}
Hien Nguyen
  • 24,551
  • 7
  • 52
  • 62