I am using an object but inside object I have a property that is a list of objects. I want to pass that object with the list objects inside it but the list is empty when I submit my form. I am not sure how to handle this.
Class
public class VSTAttendance
{
public int MemberID { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public bool Attendant { get; set; }
}
public class ServiceAttendance
{
public int AttendanceID { get; set; }
public int AttendanceTypeID { get; set; }
public string AttendanceType { get; set; }
public DateTime Service { get; set; }
public int ServiceID { get; set; }
public string Speaker { get; set; }
public string Location { get; set; }
public int HeadCount { get; set; }
public int CategoryID { get; set; }
public string Description { get; set; }
public string ChurchNotes { get; set; }
public string ServingNotes { get; set; }
public DateTime DateCreated { get; set; }
public DateTime CreatedBy { get; set; }
public DateTime DateUpdate { get; set; }
public DateTime UpdateBy { get; set; }
public List<VSTAttendance> MemberAttendance { get; set; }
}
HTML
@using (Html.BeginForm("Attendance", "Home", FormMethod.Post, new { ReturnUrl = ViewBag.ReturnUrl, @class = "form-horizontal", role = "form" }))
{
<div class="form-group">
<label for="inputSpeaker" class="col-sm-2 control-label">
Speaker</label>
<div class="col-sm-6">
@Html.TextBoxFor(m => m.Speaker, new { @class = "form-control", placeholder = "Speaker", type = "text", required = "required " })
</div>
</div>
<table class="table table-bordered table-condensed table-hover">
<tr class="warning">
<td></td>
<td>Name</td>
<td>Surname</td>
</tr>
@foreach (var item in Model.MemberAttendance)
{
<tr>
<td>@Html.CheckBox("Attendant")</td>
<td>@item.Name</td>
<td>@item.Surname</td>
</tr>
}
</table>
<div class="form-group">
<div class="col-sm-10">
<button type="submit" class="btn btn-info">
<span class="glyphicon glyphicon-ok"></span>Submit</button>
</div>
</div>
}
You have to use for instead of foreach and use Hidden for . I have tested the following and works perfect
@model ServiceAttendance
@{
ViewBag.Title = "Attendance";
}
<h2>Attendance</h2>
@using (Html.BeginForm())
{
<div class="form-group">
<label for="inputSpeaker" class="col-sm-2 control-label">
Speaker
</label>
<div class="col-sm-6">
@Html.TextBoxFor(modelItem => modelItem.Speaker)
</div>
</div>
<table class="table table-bordered table-condensed table-hover">
<tr class="warning">
<td></td>
<td>Name</td>
<td>Surname</td>
</tr>
@for (int i=0;i<Model.MemberAttendance.Count ;i++)
{
<tr>
<td>@Html.CheckBoxFor(it=>Model.MemberAttendance[i].Attendant)
@Html.HiddenFor(it => Model.MemberAttendance[i].Attendant)
</td>
<td>@Model.MemberAttendance[i].Name
@Html.HiddenFor(it => Model.MemberAttendance[i].Name)</td>
<td>@Model.MemberAttendance[i].Surname
@Html.HiddenFor(it=>Model.MemberAttendance[i].Surname)</td>
</tr>
}
</table>
<div class="form-group">
<div class="col-sm-10">
<button type="submit" class="btn btn-info">
<span class="glyphicon glyphicon-ok"></span>Submit
</button>
</div>
</div>
}
So what you have to do is replace the foreach with the following
@for (int i=0;i<Model.MemberAttendance.Count ;i++)
{
<tr>
<td>@Html.CheckBoxFor(it=>Model.MemberAttendance[i].Attendant)
@Html.HiddenFor(it => Model.MemberAttendance[i].Attendant)
</td>
<td>@Model.MemberAttendance[i].Name
@Html.HiddenFor(it => Model.MemberAttendance[i].Name)</td>
<td>@Model.MemberAttendance[i].Surname
@Html.HiddenFor(it=>Model.MemberAttendance[i].Surname)</td>
</tr>
}
Check out the BeginCollectionItem html helper available on nuget or here: https://github.com/danludwig/BeginCollectionItem
You can see more information on the behavior on this blog: http://weblogs.asp.net/nmarun/archive/2010/03/13/asp-net-mvc-2-model-binding-for-a-collection.aspx
The default model binder is expecting the names to come in this form:
MemberAttendance[0].Prop = "prop"
MemberAttendance[0].BoolProp = false
so you need to name the inputs similarly:
<input type="checkbox" name="MemberAttendance[0].Attendant" />
<input type="hidden" name="MemberAttendance[0].Name" value="Nick" />
<input type="hidden" name="MemberAttendance[0].MemberId" value="1" /> <!-- the hiddens are to maintain state of the rest of the properties -->
<input type="checkbox" name="MemberAttendance[1].Attendant" />
<input type="hidden" name="MemberAttendance[1].Name" value="Someone else" />
<input type="hidden" name="MemberAttendance[1].MemberId" value="2" />
You did not output any part of MemberAttendance
to post back. You just output its contents.
Minimal changes to your code would be to change the foreach
:
@for (int i=0; i<Model.MemberAttendance.Count; i++)
{
...your current html
@Html.HiddenFor(m => m.MemberAttendance[i].MemberID);
@Html.HiddenFor(m => m.MemberAttendance[i].Name);
@Html.HiddenFor(m => m.MemberAttendance[i].Surname);
@Html.HiddenFor(m => m.MemberAttendance[i].Attendant);
}
IF that is what you really want to do.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With