Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

id & name error when using an EditorTemplate

It took about 3 hours for me to be sure why the following (explained) error happening; and finally I'm sure that it's an mvc error. I would like to ask your opinions.

I've created an editor template and put it under the ~/Shared/EditorTemplates folder. And I carefully used the file name to be equal with type name (because I don't want to use the second parameter with "@Html.EditorFor" helper method). As a result editor template was working fine : Except the postbacks; I definately couldn't get values from model because the model was always null. I tried to change the id & names of inputs and selects carefully and did the post back: it's working fine.

So; the problem is: when I use the editorTemplate it gives "Question.[0].QuestionContext" as a name and "Question__0_QuestionContext" as an id for inputs and selects; however I was expecting "Question[0].QuestionContext" as a name and "Question_0__QuestionContext" as an id.

Then I realized that I was using @foreach inside the EditorTemplate. Then I switch back to @for but nothing changed. You can find the template below:

@using DenemeMvc3Application3.Helpers;
@model DenemeMvc3Application3.Controllers.LocalizedNameViewModels

<table>
    <thead>
        <tr>
            <td>@Html.LabelFor(modelItem => modelItem.ElementAtOrDefault(0).LanguageDropDownList)</td>
            <td>@Html.LabelFor(modelItem => modelItem.ElementAtOrDefault(0).Value)</td>
        </tr>
    </thead>
    <tbody>
    @for (int index = 0; index < Model.Count; index++)
    {
        @Html.EditorFor(modelItem => modelItem[index])
    }
    </tbody>
</table>

So I changed my template to easier one by declaring the foreach loop outside of the editortemplate & inside of the view and using the editor template only for singular item. And it worked. So I made a small investigation on how templating works on mvc3 by using reflector; and I found the bug I suppose:

The problem is caused by System.Web.Mvc.TemplateInfo class's public string GetFullHtmlFieldName(string partialFieldName) method which is used by System.Web.Mvc.Html.SelectExtensions class's private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, string optionLabel, string name, IEnumerable selectList, bool allowMultiple, IDictionary htmlAttributes) method. So as a result whenever we use @Html.DropDownListFor(/blah blah/) inside a foreach or a for loop in an EditorTemplate we get the error.

I also want to show you the bug-code below to clarify:

    // TemplateInfo method
public string GetFullHtmlFieldName(string partialFieldName)
{
    /*Here's the extra dot: causing the error.*/
    return (this.HtmlFieldPrefix + "." + (partialFieldName ?? string.Empty)).Trim(new char[] { '.' });
}

// SelectExtensions method
private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, string optionLabel, string name, IEnumerable<SelectListItem> selectList, bool allowMultiple, IDictionary<string, object> htmlAttributes)
{
    /* blah blah */
    string fullHtmlFieldName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
    /* blah blah */
}

// SelectExtensions method -> @Html.DropDownListFor
private static MvcHtmlString DropDownListHelper(HtmlHelper htmlHelper, string expression, IEnumerable<SelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes)
{
    return htmlHelper.SelectInternal(optionLabel, expression, selectList, false, htmlAttributes);

So, what are your thoughts?

like image 458
Mert Susur Avatar asked May 31 '26 03:05

Mert Susur


1 Answers

Then I realized that I was using @foreach inside the EditorTemplate. Then I switch back to @for but nothing changed.

How about getting rid of all loops and simply:

@model IEnumerable<FooViewModel>
<table>
    <thead>
        <tr>
            <td>@Html.LabelFor(modelItem => modelItem.ElementAtOrDefault(0).LanguageDropDownList)</td>
            <td>@Html.LabelFor(modelItem => modelItem.ElementAtOrDefault(0).Value)</td>
        </tr>
    </thead>
    <tbody>
        @Html.EditorForModel()
    </tbody>
</table>

Much better? No loops and correct names and ids. It's ASP.NET MVC that will automatically render the editor template for each element of your model collection.

and the corresponding editor template (~/Views/Shared/EditorTemplates/FooViewModel.cshtml):

@model FooViewModel
<tr>
    <td>@Html.EditorFor(x => x.SomeProperty)</td>
    <td>@Html.EditorFor(x => x.SomeOtherProperty)</td>
</tr>
like image 152
Darin Dimitrov Avatar answered Jun 01 '26 15:06

Darin Dimitrov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!