Search code examples
asp.netasp.net-mvcasp.net-mvc-3razormvc-editor-templates

Editor template doesn't work after calling Ajax.BeginForm and Html.BeginForm


I created an editor template for enums which was working fine, until I decided to use Ajax.BeginForm. The property status has the following definition:

<DisplayName("Status")>
<UIHint("enum")>
Public Property status As String

I already tried the following approachs:

@Using Ajax.BeginForm("New", "Os", Nothing)
    @Html.EditorFor(Function(m) m.status, "Enum", New With { .enumType = GetType(OsStatus)})
End Using

@Ajax.BeginForm("New", "Os", Nothing)

@Html.EditorFor(Function(m) m.status, "Enum", New With { .enumType = GetType(OsStatus)})

@Using Html.BeginForm()
    @Html.EditorFor(Function(m) m.status, "Enum", New With { .enumType = GetType(OsStatus)})
End Using

@Html.BeginForm()
@Html.EditorFor(Function(m) m.status, "Enum", New With { .enumType = GetType(OsStatus)})

None of the above worked.

The code for my template is as follows

@ModelType String

@code

    Dim options As IEnumerable(Of OsStatus)
    options = [Enum].GetValues(ViewData("enumType")).Cast(Of OsStatus)()


    Dim list As List(Of SelectListItem) = 
            (from value in options 
            select new SelectListItem With { _
                .Text = value.ToString(), _
                .Value = value.ToString(), _
                .Selected = value.Equals(Model) _
            }).ToList()
    End If
End Code

@Html.DropDownList(Model, list)

After calling a .BeginForm method, my template is still called, but the Model property inside my template is null.

ANY ideas?


Solution

  • I can see at least 4 issues with your editor template:

    • You have an End If without an opening If so your editor template is likely to throw an exception
    • In order to determine the selected value you are comparing an enum value to a string: value.Equals(Model) whereas you should be comparing string with string: value.ToString().Equals(Model)
    • When rendering your dropdownlist you are using your Model value as name whereas you should be using an empty string in order to have correct name for this dropdownlist from the parent property.
    • Your editor template is now tied to the OsStatus enum as you are casting to it inside it. It would have been better to make this editor template a little more generic and reusable.

    Here's the correct way:

    @ModelType String
    
    @code
        Dim options = [Enum].GetValues(ViewData("enumType")).Cast(Of Object)()
    
        Dim list As List(Of SelectListItem) =
                (From value In options
                Select New SelectListItem With { _
                    .Text = value.ToString(), _
                    .Value = value.ToString(), _
                    .Selected = value.ToString().Equals(Model) _
                }).ToList()
    End Code
    
    @Html.DropDownList("", list)
    

    And the correct way to invoke it is:

    @Using Ajax.BeginForm("New", "Os", Nothing)
        @Html.EditorFor(Function(m) m.status, "Enum", New With { .enumType = GetType(OsStatus)})
    End Using
    

    or:

    @Using Html.BeginForm("New", "Os", Nothing)
        @Html.EditorFor(Function(m) m.status, "Enum", New With { .enumType = GetType(OsStatus)})
    End Using
    

    Now when rendering this view make sure that the controller action actually passed a model and have the status string property set to some string value that is contained within the enum so that the correct option could be automatically pre-selected in the dropdown.