8

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>

}

4 Answers 4

15

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>
            }
Sign up to request clarification or add additional context in comments.

3 Comments

Why do I need to use HiddenFor? What is the purpose for it?
Consider using a partial view inside your loop, would make your code much cleaner.
This helped me. Also my object was an ICollection I had to change this to a List in order for the model to pass back to the controller properly.
3

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

Comments

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.

Comments

0

Thank you ! it is work with me

                            <input type="text" id="tenhangid" class="formelement"
                                   value="@Model.tempdetail[i].tenhang"
                                   new { onkeydown="return  event.keyCode != 13" }
                                   [email protected][i].tenhang
                                   name="@Model.tempdetail[i].tenhang"
                                   disabled="disabled"
                                   
                                   >





                        </td>


                        <td>
                            <form method="post" asp-controller="Home" asp-action="xoadetailtranferout">
                                <input type="hidden" asp-controller="Home" asp-action="xoadetailtranferout" name="idxoa" [email protected][i].id />

                                <button class="btn1" type="submit" asp-controller="Home" asp-action="xoadetailtranferout">Xóa</button>

                            </form>


                        </td>


                        @Html.HiddenFor(m => m.tempdetail[i].tenhang );
                        @Html.HiddenFor(m => m.tempdetail[i].donvitinh);
                        @Html.HiddenFor(m => m.tempdetail[i].Expireddate);
                        @Html.HiddenFor(m => m.tempdetail[i].soluong);
                        @Html.HiddenFor(m => m.tempdetail[i].mahang);


                    </tr>

1 Comment

Please don't add "thank you" as an answer. Instead, vote up the answers that you find helpful. - From Review

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.