DrewB
DrewB

Reputation: 1536

Create dynamic forms in ASP.NET MVC

I have an ASP.NET MVC application that tracks vendors for our company by purchase orders. Each PO rating is assigned a type. Each type can have multiple rating sections and each rating section can have multiple categories. The classes look like that:

public class RatingModel{
    /*Fields for the purchase order*/

    public List<RatingSectionModel> RatingSections { get; set; }
}

public class RatingSectionModel {
    /*Fields for the Rating section*/

    public List<RatingCategoryModel > Categories { get; set; }
}

public class RatingCategoryModel {
    /*Fields for the category*/
}

In my project, I am attempting to use the modified BeginCollectionItem found here. The cshtml is:

_RatingModel.cshtml:

@model VendorRating.Models.RatingModel
@Html.HiddenFor(model => model.VendorId)
@Html.HiddenFor(model => model.VendorName)
@Html.HiddenFor(model => model.AwardDate)
@Html.HiddenFor(model => model.AwardValue)
@Html.HiddenFor(model => model.CloseDate)
@Html.HiddenFor(model => model.FinalValue)
@Html.HiddenFor(model => model.ServiceRep)
@Html.HiddenFor(model => model.PoId)

<div style="display:table;margin-bottom:5px;">
    <div style="display:table-row">
        <div style="display:table-cell;vertical-align:top;">
            @Html.LabelFor(model => model.TypeId)
        </div>
        <div style="display:table-cell;vertical-align:top;">
            @Html.DropDownListFor(model => model.TypeId, Model.Types)
        </div>
    </div>
</div>
<table>
    <tr>
        <td class="table-header">@Html.LabelFor(model => model.PoId, htmlAttributes: new { @class = "control-label" })</td>
        <td class="table-header">@Html.LabelFor(model => model.VendorName, htmlAttributes: new { @class = "control-label" })</td>
        <td class="table-header">@Html.LabelFor(model => model.AwardDate, htmlAttributes: new { @class = "control-label" })</td>
        <td class="table-header">@Html.LabelFor(model => model.AwardValue, htmlAttributes: new { @class = "control-label" })</td>
    </tr>
    <tr>
        <td>@Html.DisplayFor(model => model.PoId, new { htmlAttributes = new { @class = "form-control" } })</td>
        <td>@Html.DisplayFor(model => model.VendorName, new { htmlAttributes = new { @class = "form-control" } })</td>
        <td>@Html.DisplayFor(model => model.AwardDate, new { htmlAttributes = new { @class = "form-control" } })</td>
        <td>@Html.DisplayFor(model => model.AwardValue, new { htmlAttributes = new { @class = "form-control" } })</td>
    </tr>
    <tr>
        <td class="table-header">@Html.LabelFor(model => model.CloseDate, htmlAttributes: new { @class = "control-label" })</td>
        <td class="table-header" ">@Html.LabelFor(model => model.FinalValue, htmlAttributes: new { @class = "control-label" })</td>
        <td class="table-header" ">@Html.LabelFor(model => model.ServiceRep, htmlAttributes: new { @class = "control-label" })</td>
    </tr>
    <tr>
        <td>@Html.DisplayFor(model => model.CloseDate, new { htmlAttributes = new { @class = "form-control" } })</td>
        <td>@Html.DisplayFor(model => model.FinalValue, new { htmlAttributes = new { @class = "form-control" } })</td>
        <td>@Html.DisplayFor(model => model.ServiceRep, new { htmlAttributes = new { @class = "form-control" } })</td>
    </tr>
</table>
<div id="sections">
    @{
        if(Model.Sections != null) {
            @Html.EditorFor(model => model.Sections)

        }
    }

RatingSectionModel.cshtml:

@model List<VendorRating.Models.RatingSectionModel>

@{
    var id = "";

    foreach(VendorRating.Models.RatingSectionModel sectionModel in Model) {
        using(Html.BeginCollectionItem("Sections", out id)) {

            <fieldset style="margin-top:10px;">
                <legend style="font-weight:bold;">
                    @sectionModel.SectionName
                    @Html.HiddenFor(model => sectionModel.SectionId)
                </legend>
                <div style="display:table;width:100%">

                    @foreach(VendorRating.Models.RatingCategoryModel c in sectionModel.RatingCategories) {
                        @Html.EditorFor(cat => c);
                    }
                    <div style="display:table-row;width:100%">
                        <div style="display:table-cell;width:70%"></div>
                        <div style="display:table-cell;text-align:right;width:10%"></div>
                        <div style="display:table-cell;text-align:right;width:10%">Total</div>
                        <div style="display:table-cell;text-align:right;width:10%;"><div data-section-total="@sectionModel.SectionId" style="width:50%;border-bottom:solid 1px lightgray;text-align:right;"></div></div>
                    </div>
                </div>
            </fieldset>
            <script>
                function changeTotals() {
                    var totalScore = 0;
                    $('#poForm').find('*[data-section-score="@sectionModel.SectionId"]').each(function () {
                        var val = parseFloat($(this).text());

                        if (!isNaN(val)) {
                            totalScore = totalScore + val;
                        }
                    });

                    $('#poForm').find('*[data-section-total="@sectionModel.SectionId"]').text(totalScore);
                }
            </script>
        }
    }
}

The fields are generated correctly, but when I examine the form, the name of each field is Sections[sectionid here].sectionModel.FieldName. The sectionModel being inserted into the name is keeping it from binding properly with the Sections collection when the form is submitted. The proper number of sections are added to the collection, but all of their properties are empty. I'm sure I have something set up wrong here, but I have no idea what it could be.

Upvotes: 0

Views: 1641

Answers (1)

Daniel Gpe Reyes
Daniel Gpe Reyes

Reputation: 417

You should change your foreach to for, and the binding will work!

Upvotes: 1

Related Questions