Search code examples
c#asp.net-mvcrazorrazor-declarative-helpers

Stuck on Razor extension


I'm trying to refactor some commonly-used code into a helper extension and am stuck with the syntax, largely because I don't have a full grip of generics, lambda expressions etc.

I'd like to be able to put this in my view, and for it to use my model's field (eg FirstName) to produce some HTML that makes use of other Razor extensions:

@MyHelpers.BootstrapFormItem(m => m.FirstName)

At the moment I've got:

@using System.Web.Mvc;
@using System.Web.Mvc.Html;
@using System.Linq;
@using System.Linq.Expressions;

@helper BootstrapFormitem(XXXXXXXXX) 
{
         <div class="control-group">
            @Html.LabelFor(XXXXXXX)
            <div class="controls">
               @Html.DisplayFor(XXXXX)
               @Html.ValidationMessageFor(XXXX)
            </div>
         </div>
}

Questions:

  1. Is this the right approach? I'd like to be able to use this method with any viewmodel field.
  2. Have I included the right namespaces? This will go in the app_code folder
  3. What goes in XXXXXX?

Solution

  • This class do what you need, I use these all the time:

    using System;
    using System.Linq.Expressions;
    using System.Text;
    using System.Web.Mvc;
    using System.Web.Mvc.Html;
    
    public static class HtmlHelpers
    {
        public static MvcHtmlString BootstrapFormItem<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression)
        {
            StringBuilder html = new StringBuilder("<div class=\"control-group\">");
            html.AppendLine(helper.LabelFor(expression).ToString());
            html.AppendLine("<div class=\"controls\">");
            html.AppendLine(helper.DisplayFor(expression).ToString());
            html.AppendLine(helper.ValidationMessageFor(expression).ToString());
            html.AppendLine("</div>");
            html.AppendLine("</div>");
            return MvcHtmlString.Create(html.ToString());
        }
    }
    

    Note that this is a static class and also an extension method, the first input parameter is prefixed with 'this' which means it will extend (show up after you type a '.' in Intellisense) any objects of type HtmlHelper<TModel>. I will generally put this class in a Utilities folder. I often use a namespace as well and reference it from the web.config.

    EDIT TO ANSWER QUESTIONS:

    Here is the usage, it is covered by Intellisense as well:

    @model MyClass
    
    @Html.BootstrapFormItem(x => x.Name)
    

    This is the output:

    <div class="control-group">
        <label for="Name">Name</label>
        <div class="controls">
            naspinski
            <span class="field-validation-valid" data-valmsg-for="Name" data-valmsg-replace="true"/>
        </div>
    </div>