zmbq
zmbq

Reputation: 39023

Getting full property name using ModelMetadata

I'm trying to create an HtmlHelper that will create Bootstrap-compatible form fields. My first goal was to create an HtmlHelper that will create the surrounding div:

<div class="control-group"> ... </div>

Following the excellent advice here and also here I managed to get it to work relatively quickly. But it doesn't always work.

I have a ViewModel with a complex property, so in my form I access the field m=>m.Complex.Element . In my helper I check the element for validation errors. I use ModelMetadata.FromLambdaExpression(expression, html.ViewData) . The metadata I get back has the property name Element, and not Complex.Element.

When I check the ModelState for this property, I can't find it, because the ModelState keeps the full name - Complex.Element.

I can look for partial matches, hoping there's no other Element, but that seems like a nasty bug waiting to happen. How can I get the full property name from the expression?

Upvotes: 15

Views: 5753

Answers (3)

zmbq
zmbq

Reputation: 39023

It's a good thing the MVC sources are out in the open. The proper way to get the ModelState property name is by using

var propertyName = ExpressionHelper.GetExpressionText(expression);

Upvotes: 32

Adrian Thompson Phillips
Adrian Thompson Phillips

Reputation: 7138

I've used a combination of both answers for an attribute I needed. Together, both of these answers provide a working attribute I can use in both views and nested editor templates. Here's my example:

public static MvcHtmlString HasErrorClassFor<TModel, TProperty>(
    this HtmlHelper<TModel> htmlHelper,
    Expression<Func<TModel, TProperty>> expression)
{
    string expressionText = ExpressionHelper.GetExpressionText(expression);

    string htmlFieldPrefix = htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix;

    string fullyQualifiedName;

    if (htmlFieldPrefix.Length > 0)
    {
        fullyQualifiedName = string.Join(".", htmlFieldPrefix, expressionText);
    }
    else
    {
        fullyQualifiedName = expressionText;
    }

    bool isValid = htmlHelper.ViewData.ModelState.IsValidField(fullyQualifiedName);

    if (!isValid)
    {
        return MvcHtmlString.Create("has-error");
    }

    return MvcHtmlString.Empty;
}

Upvotes: 4

Betty
Betty

Reputation: 9189

I've used the following to get it for the current model before, you may have to append the property name to this to get it for the property though.

ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix;

Otherwise pull out reflector/ilspy/whatever and check what your EditorFor/TextBoxFor or whatever method is rendering your editor does.

Upvotes: 7

Related Questions