Wednesday, February 2, 2011

HtmlHelper Extensions

I'll keep this fairly short. Do yourself a favor and organize your HtmlHelper extensions. That thing gets polluted quick and you'll find yourself with pages of items in intellisense and large method signatures for your configuration options.

I suggest trying an idea of having HtmlHelper extensions that create and return custom html builders for related or even individual UI widgets. The builders can have a fluent interface for more complicated configuration of the output and you get the added benefit of keeping the HtmlHelper somewhat clean.

Here is an example of what I'm suggesting.

Clean simple HtmlHelper extensions:

public static class HtmlHelperExtensions
{
  public static PhoneHtmlBuilder<tmodel> Phone(this HtmlHelper<tmodel> helper)
  {
    return new PhoneHtmlBuilder<tmodel>(helper);
  }

  //... a bunch of other things
}

With Html Builders doing the real work, possibly grouping related widgets (as I'm calling them):

public class PhoneHtmlBuilder<tmodel>
{
  private HtmlHelper<tmodel> _helper;
  private Expression<Func<TModel, string>> _phoneNumber;
  private Expression<Func<TModel, string>> _extension;

  public PhoneHtmlBuilder(HtmlHelper<tmodel> helper)
  {
    _helper = helper;
  }

  public PhoneHtmlBuilder<tmodel> For(Expression<Func<TModel, string>> property)
  {
    _phoneNumber = property;
    return this;
  }

  public PhoneHtmlBuilder<tmodel> WithExtension(Expression<Func<TModel, string>> property)
  {
    _extension = property;
    return this;
  }

  public MvcHtmlString Render()
  {
    //probably register javascript to get rendered or generate some

    //i'm not even sure if this compiles, just getting a basic format of the idea down
    return MvcHtmlString.Create(
      _helper.LabelFor(_property) +
      _helper.TextBoxFor(_property) +
      _withExtension ? _helper.TextBoxFor(_extension) : "" +
      _helper.ValidationMessageFor(_property));
  }

  public override string ToString()
  {
    return Render().ToString();
  }
}

Providing organization and possibly fluent or more options for the more complex widgets:



  

Cell Phone

@Html.Phone().For(m => m.Cell)

Business Line

@Html.Phone().For(m => m.BusinessNumber) .WithExtension(m => m.BusinessExtension) .Render()

Note that the call to Render() for the business number was optional, just trying to show options.

I hope that's helpful. I would love to hear any feedback or ideas.

No comments:

Post a Comment