1

I am using the approach in this article to return a list of objects that are posted to my action. My method looks like:

    //
    // POST: /LeaveRequest/Create
    [Authorize, HttpPost]
    public ActionResult Create(LeaveRequest leaveRequest, IEnumerable<DayRequested> requestedDays)
    {
        return RedirectToAction("Index", lrRepository.GetLeaveRequests(472940821));
    }

leaveRequest has the data that I expect. requestedDays contains the number of rows I expect, but all of the rows contain null in each field. Any ideas of what I may be missing?

Here is the View code:

Create.aspx

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<EmployeePayroll.ViewModels.LeaveRequestViewModel>" %>
<%@ Import Namespace="EmployeePayroll.Helpers"%>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">Create New Leave Request</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2>Create New Leave Request</h2>
    <div><%= Html.ActionLink("Back to List", "Index") %></div>
    <%= Html.Partial("RequestEditor", Model) %>
    <div><%= Html.ActionLink("Back to List", "Index") %></div>
</asp:Content>

RequestEditor.ascx

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<EmployeePayroll.ViewModels.LeaveRequestViewModel>" %>
<% using (Html.BeginForm()) {%>
    <%= Html.ValidationSummary(true) %>
    <fieldset>
        <legend>Request Details</legend>
        <table>
             <tbody id="editorRows">
                <tr><th>Date</th><th>Time</th><th>Hours</th><th>Request Type</th><th></th></tr>
                <% foreach (var item in Model.DaysRequested)
                    Html.RenderPartial("RequestedDayRow", new EmployeePayroll.ViewModels.LeaveRequestRow(item, Model.LeaveRequestType)); %>
            </tbody>
        </table>
        <p><%= Html.ActionLink("Add Day", "BlankRequestedDayRow", null, new { id = "addItem" })%></p>

        <p>Type your time to sign your request.</p>
        <p><%= Html.LabelFor(model => model.LeaveRequest.EmployeeSignature) %>: <%= Html.TextBoxFor(model => model.LeaveRequest.EmployeeSignature, new { Class="required" })%></p>
        <p><%= Html.LabelFor(model => model.LeaveRequest.EmployeeComment) %>: <%= Html.TextBoxFor(model => model.LeaveRequest.EmployeeComment) %></p>
        <p><input type="submit" value="Submit Request" /></p>
    </fieldset>
<% } %>

RequestedDayRow.ascx

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<EmployeePayroll.ViewModels.LeaveRequestRow>" %>
<%@ Import Namespace="EmployeePayroll.Helpers"%>

<tr class="editorRow">
    <% using (Html.BeginCollectionItem("requestedDays"))
   { %>
        <td><%= Html.TextBoxFor(model => model.DayRequested.DateOfLeave, new { Class = "datepicker", Maxlength = "10" })%></td>
        <td><%= Html.TextBoxFor(model => model.DayRequested.TimeOfLeave, new { Class = "timedropdown", Maxlength = "8" })%></td>
        <td><%= Html.TextBoxFor(model => model.DayRequested.HoursRequested, new { Class = "hoursdropdown", Maxlength = "4" })%></td>
        <td><%= Html.DropDownListFor(model => model.DayRequested.RequestType, 
            new SelectList(Model.LeaveRequestType, "Value", "Text", Model.DayRequested.RequestType), "(Select)")%></td>
        <td><a href="#" class="deleteRow"><img src="../../images/site_icons/16/69.png" title="Delete" alt="Delete" border="0" /></a></td>
    <% } %>
</tr>

Here is the generated form:

<form method="post" action="/LeaveRequest/Create">
    <fieldset>
        <legend>Request Details</legend>
        <table>
            <tbody id="editorRows">
                <tr><th>Date</th><th>Time</th><th>Hours</th><th>Request Type</th><th></th></tr>
<tr class="editorRow">
    <input type="hidden" value="c43391a3-7fe4-4514-8b27-d00995d64848" autocomplete="off" name="requestedDays.index">

        <td><input type="text" value="11/17/2010" name="requestedDays[c43391a3-7fe4-4514-8b27-d00995d64848].DayRequested.DateOfLeave" id="requestedDays_c43391a3-7fe4-4514-8b27-d00995d64848__DayRequested_DateOfLeave" maxlength="10" class="datepicker"></td>
        <td><input type="text" value="8:00 AM" name="requestedDays[c43391a3-7fe4-4514-8b27-d00995d64848].DayRequested.TimeOfLeave" id="requestedDays_c43391a3-7fe4-4514-8b27-d00995d64848__DayRequested_TimeOfLeave" maxlength="8" class="timedropdown"></td>
        <td><input type="text" value="8" name="requestedDays[c43391a3-7fe4-4514-8b27-d00995d64848].DayRequested.HoursRequested" id="requestedDays_c43391a3-7fe4-4514-8b27-d00995d64848__DayRequested_HoursRequested" maxlength="4" class="hoursdropdown"></td>
        <td><select name="requestedDays[c43391a3-7fe4-4514-8b27-d00995d64848].DayRequested.RequestType" id="requestedDays_c43391a3-7fe4-4514-8b27-d00995d64848__DayRequested_RequestType"><option value="">(Select)</option>
</select></td>
        <td><a class="deleteRow" href="#"><img border="0" alt="Delete" title="Delete" src="../../images/site_icons/16/69.png"></a></td>
</tr>
<tr class="editorRow">
    <input type="hidden" value="a24b74f6-2947-4ec5-a817-f938d6fe4e24" autocomplete="off" name="requestedDays.index">
        <td><input type="text" value="11/17/2010" name="requestedDays[a24b74f6-2947-4ec5-a817-f938d6fe4e24].DayRequested.DateOfLeave" id="requestedDays_a24b74f6-2947-4ec5-a817-f938d6fe4e24__DayRequested_DateOfLeave" maxlength="10" class="datepicker"></td>
        <td><input type="text" value="8:00 AM" name="requestedDays[a24b74f6-2947-4ec5-a817-f938d6fe4e24].DayRequested.TimeOfLeave" id="requestedDays_a24b74f6-2947-4ec5-a817-f938d6fe4e24__DayRequested_TimeOfLeave" maxlength="8" class="timedropdown"></td>
        <td><input type="text" value="8" name="requestedDays[a24b74f6-2947-4ec5-a817-f938d6fe4e24].DayRequested.HoursRequested" id="requestedDays_a24b74f6-2947-4ec5-a817-f938d6fe4e24__DayRequested_HoursRequested" maxlength="4" class="hoursdropdown"></td>
        <td><select name="requestedDays[a24b74f6-2947-4ec5-a817-f938d6fe4e24].DayRequested.RequestType" id="requestedDays_a24b74f6-2947-4ec5-a817-f938d6fe4e24__DayRequested_RequestType"><option value="">(Select)</option>
</select></td>
        <td><a class="deleteRow" href="#"><img border="0" alt="Delete" title="Delete" src="../../images/site_icons/16/69.png"></a></td>
</tr>
</tbody>
    </table>
    <p><a id="addItem" href="/LeaveRequest/BlankRequestedDayRow">Add Day</a></p>

    <p>Type your time to sign your request.</p>
    <p><label for="LeaveRequest_EmployeeSignature">Employee Signature</label>: <input type="text" value="" name="LeaveRequest.EmployeeSignature" id="LeaveRequest_EmployeeSignature" class="required"></p>
    <p><label for="LeaveRequest_EmployeeComment">Employee Comment</label>: <input type="text" value="" name="LeaveRequest.EmployeeComment" id="LeaveRequest_EmployeeComment"></p>
    <p><input type="submit" value="Submit Request"></p>
</fieldset>
</form>

The form posts the following information:

Parametersapplication/x-www-form-urlencoded
LeaveRequest.EmployeeComm...    Comment
LeaveRequest.EmployeeSign...    Michael Wills
requestedDays.index 549a7c9a-9c7d-4032-a1cd-6bfda92bf1f2
requestedDays.index 2838b025-d971-4d98-a081-5ea0c559aebb
requestedDays[2838b025-d9...    11/17/2010
requestedDays[2838b025-d9...    8
requestedDays[2838b025-d9...    1
requestedDays[2838b025-d9...    8:00 AM
requestedDays[549a7c9a-9c...    11/17/2010
requestedDays[549a7c9a-9c...    8
requestedDays[549a7c9a-9c...    1
requestedDays[549a7c9a-9c...    8:00 AM
Source
Content-Type: application/x-www-form-urlencoded
Content-Length: 907
requestedDays.index=549a7c9a-9c7d-4032-a1cd-6bfda92bf1f2&requestedDays%5B549a7c9a-9c7d-4032-a1cd-6bfda92bf1f2%5D.DayRequested.DateOfLeave=11%2F17%2F2010&requestedDays%5B549a7c9a-9c7d-4032-a1cd-6bfda92bf1f2%5D.DayRequested.TimeOfLeave=8%3A00+AM&requestedDays%5B549a7c9a-9c7d-4032-a1cd-6bfda92bf1f2%5D.DayRequested.HoursRequested=8&requestedDays%5B549a7c9a-9c7d-4032-a1cd-6bfda92bf1f2%5D.DayRequested.RequestType=1&requestedDays.index=2838b025-d971-4d98-a081-5ea0c559aebb&requestedDays%5B2838b025-d971-4d98-a081-5ea0c559aebb%5D.DayRequested.DateOfLeave=11%2F17%2F2010&requestedDays%5B2838b025-d971-4d98-a081-5ea0c559aebb%5D.DayRequested.TimeOfLeave=8%3A00+AM&requestedDays%5B2838b025-d971-4d98-a081-5ea0c559aebb%5D.DayRequested.HoursRequested=8&requestedDays%5B2838b025-d971-4d98-a081-5ea0c559aebb%5D.DayRequested.RequestType=1&LeaveRequest.EmployeeSignature=Michael+Wills&LeaveRequest.EmployeeComment=Comment
Dan Atkinson
  • 11,391
  • 14
  • 81
  • 114
Mike Wills
  • 20,959
  • 28
  • 93
  • 149
  • I know I am not doing anything with the data in my method yet. I was validating what I was getting before moving on. – Mike Wills Nov 17 '10 at 21:46
  • You shouldn't need the '.Index' hidden form field anymore. In fact, I think it actually breaks in ASP.NET MVC 2. Try taking that out. – Dan Atkinson Nov 17 '10 at 21:50
  • @Dan Atkinson - That made it worse, the object is now `null` – Mike Wills Nov 17 '10 at 21:55
  • Okay. Shouldn't the field be `requestedDays[a24b74f6-2947-4ec5-a817-f938d6fe4e24].HoursRequested` (eg not having `DayRequested` in)? – Dan Atkinson Nov 17 '10 at 22:01
  • I am using a ViewModel to pass in multiple objects into the View. So that is what MVC 2 is generating automatically. I'll post the view code. – Mike Wills Nov 17 '10 at 22:06
  • Is it possible to manually code it and see what happens? I'm convinced that the DayRequested shouldn't need to be after the `[]` (seeing as it would already know which property to bind the value to). – Dan Atkinson Nov 17 '10 at 22:11
  • It's not clear from your sample what the `LeaveRequestRow` model is. – Dan Atkinson Nov 17 '10 at 22:25
  • @Dan Atkinson - That worked per just like the answer I marked as the answer. – Mike Wills Nov 17 '10 at 22:39

2 Answers2

0

see this post from Haacked - Model Binding To A List it might help you

moi_meme
  • 9,180
  • 4
  • 44
  • 63
0

Looks like you may need to remove DayRequested from your hidden form field name.

For example:

... I removed some of the attributes because the only thing that's changed here is the name attribute.
<input type="hidden" name="requestedDays[c43391a3-7fe4-4514-8b27-d00995d64848].DateOfLeave" value="11/17/2010" />
<input type="hidden" name="requestedDays[c43391a3-7fe4-4514-8b27-d00995d64848].TimeOfLeave" value="8:00 AM" />
<input type="hidden" name="requestedDays[c43391a3-7fe4-4514-8b27-d00995d64848].HoursRequested" value="8"  />
...

As discussed in the question comments, it seems odd that ASP.NET MVC would generate the source you gave, as that suggests that each RequestedDay object has a single property called RequestedDay.

The object you're binding to is called requestedDays, and the guid is an indication of which position in the collection you're binding to (stating the obvious here, I know!). Therefore, stating the object name (DayRequested) doesn't make any sense, since the model binder should already know this, and just needs to know which property of that class it's dealing with.

Dan Atkinson
  • 11,391
  • 14
  • 81
  • 114
  • Okay, I guess the article I copied the code from was wrong then. I'll this worked. I manually created the Name and ID and now it works. Thanks! – Mike Wills Nov 17 '10 at 22:38