Cannot POST complex object from View to Controller

89 views Asked by At

So I've read many of the questions already about this and can't seem to find a correlation. I have a view model that consists of another model with several collections of - you guessed it - more models:

Public Class FeeTemplateViewModel
    Public Property FeeSetup As FeeSetupModel        
    Public Property TemplateId As Integer
    Public Property Name As String
    Public Property CompanyId As Integer
    Public Property GroupId As Integer
    Public Property Users As Integer
    Public Property CreateDate As DateTime
    Public Property Modified As DateTime
    Public Property CreatedBy As String
End Class

Public Class FeeSetupModel
    <DisplayName("Office Id")>
    Property OfficeId() As String
    <DisplayName("Office Name")>
    Property OfficeName() As String
    <DisplayName("Current Fees")>
    Property CurrentFees() As IEnumerable(Of FeeItemModel)
    <DisplayName("Minimum Preparer Fee")>
    Public Property MinPFee As Decimal
    Public Property AvailableFees As List(Of FeeListItem)
    Public Property CustomFees As List(Of CustomFee)
End Class

When I post back to the controller from the view, FeeSetup is null and I can't determine why.

Controller:

<HttpPost()>
Function Edit(model As FeeTemplateViewModel) As ActionResult
    ModelState.Clear()
    If String.IsNullOrEmpty(model.Name) Then
        ModelState.AddModelError("Name", "Template name is required")
    End If
    If Not ModelState.IsValid Then
        Return View("Edit", model)
    End If
    Save(model)
    Return View("Edit")
End Function

ModelState error:

{"The parameter conversion from type 'System.String' to type 'ProAvalon.Models.Configuration.FeeSetupModel' failed because no type converter can convert between these types."}

View:

@Using Html.BeginForm("Edit", "FeeTemplate", Nothing, FormMethod.Post, Nothing)
@<div>
    @Html.HiddenFor(Function(m) m.FeeSetup)
    @If Model.TemplateId > 0 Then
        @<p><strong>Last Modified:</strong>@Model.Modified.ToLocalTime</p>
    End If

    <div class="inputsection col-md-14" id="options">
        <div class="row">
            <div>
                @Html.LabelFor(Function(m) m.Name, "Template Name")
                @Html.EditorFor(Function(m) m.Name, "TemplateName")
            </div>
        </div>
        @Html.ValidationMessageFor(Function(m) m.Name)
        <div style="height:50px;line-height:50px;">
            <div id="status-bar" style="display:none">
                <span style="font-size:16px; margin-left:5px; font-weight:bold; color: #333;" />
            </div>
        </div>
        <div class="clearfix" />
        <div id="fee-grid-wrapper" style="min-height:500px;">
            <table id="fee-grid" class="table table-striped table-condensed table-bordered table-fixed-header">
                <thead>
                    <tr class="alert-info">
                        <th style="border:none;vertical-align:top;text-transform:uppercase;">
                            <strong>Filter Forms</strong>
                        </th>
                        <th style="border: none; vertical-align: top;" colspan="3">
                            <div class="col-lg-3 col-md-3 col-sm-3 col-xs-12" style="padding:0 5px">
                                <input name="filter" type="radio" checked="checked" data-filter="" /> All forms
                            </div>
                            <div class="col-lg-4 col-md-4 col-sm-4 col-xs-12" style="padding:0 5px">
                                <input name="filter" type="radio" data-filter="fd" /> Federal Forms <br />
                                <input name="filter" type="radio" id="state-forms" /> State Forms
                                <div style="display:none" id="state-form-picker" class="state-picker">
                                    @Html.DropDownListFor(Function(m) i, ProAvalon.PageHelpers.StateSelectList)
                                </div>
                            </div>
                            <div class="col-lg-4 col-md-4 col-sm-4 col-xs-12" style="padding:0 5px" id="search-target">
                            </div>
                        </th>
                    </tr>
                    <tr style="background:#eee">
                        <th style="cursor:pointer">No.</th>
                        <th style="cursor:pointer">Fed/St</th>
                        <th style="cursor:pointer">Form/Schedule Name</th>
                        <th style="cursor:pointer">Amount</th>
                    </tr>
                </thead>
                <tfoot>
                    <tr style="background:#eee">
                        <th>No.</th>
                        <th>Fed/St</th>
                        <th>Form/Schedule Name</th>
                        <th style="min-width:300px">Amount</th>
                    </tr>
                </tfoot>
                <tbody>
                    @If Model.FeeSetup.AvailableFees IsNot Nothing Then
                            For Each fee In Model.FeeSetup.AvailableFees
                                @Html.HiddenFor(Function(m) fee)
                        @Code
                            Dim tmp As ProAvalon.Models.Configuration.FeeItemModel = Model.FeeSetup.CurrentFees.Where(Function(x) x.FormName = fee.FormName).FirstOrDefault()
                            Dim amount = 0D
                            If (tmp IsNot Nothing) Then amount = tmp.FeeAmount
                            i = i + 1
                            Html.HiddenFor(Function(m) tmp)
                        End Code
                        @<tr data-id="@(fee.FormName)">
                            <td>@(i) </td>
                            <td>@(IIf(fee.FormType = "FD", fee.FormType, IIf(fee.FormType = "BS", fee.FormState + "-BS", fee.FormState)))</td>
                            <td>@(fee.FormDesc)</td>
                            <td style="min-width:300px">
                                <span style="display:none">@amount</span> @*to enable sorting*@
                                @Html.TextBoxFor(Function(m) amount)
                                @*@(New HtmlString("<span>" + _
                            Html.TextBox("Amount_" + fee.FormName.ToString(), CType(amount, Decimal), _
                            New With {.class = "pull-left currency_input currencyTB amount_" + fee.FormName}).ToHtmlString() + _
                            "<span id=""msg_" + fee.FormName + """ style='display:none; line-height:35px;padding-left:10px;'></span></span>"))*@
                            </td>
                        </tr>
                    Next
                End If
                </tbody>
            </table>
        </div>
    </div>
</div>
@<br />
@<div>
    <hr />
    <div class="float-right" style="margin-left: 20pt">
        @Html.SubmitButton()
    </div>
    <div>
        @Html.CancelButton("Index", "FeeTemplate")
    </div>
    <div class="clear clearfix" />
</div>
End Using

I'm going to feel like a real jerk if one of you looks at this and finds a naming overlap, but I've looked through it several times and cannot determine that to be the cause.

1

There are 1 answers

2
beautifulcoder On

To begin, list binding does not work on this:

For Each fee In Model.FeeSetup.AvailableFees

You'll need to look through it using an index:

For index As Integer = 0 To Model.FeeSetup.AvailableFees.Length
    @Html.HiddenFor(Function(m) m.FeeSetup.AvailableFees[index])
Next